예제 #1
0
    def k_alpha_rate(t, delta_r_bar=0):
        if verbose:
            print(t)
        schedule(t, 1, delta_r_bar=delta_r_bar)
        # Construct the first order transition matrix
        ground_energy, ground_state = SchrodingerEquation(hamiltonians=eq.hamiltonians).ground_state()
        overlap = 0
        for op in eq.jump_operators[0].jump_operators:
            overlap = overlap - (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] + \
                      (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0]
        if graph.degeneracy > 1:
            # Solve for the k lowest eigenvalues, where k=degeneracy
            energies, states = SchrodingerEquation(hamiltonians=eq.hamiltonians).eig(k=graph.degeneracy+1)
            states = states.T
            rates_into_degenerate = np.zeros(energies.shape[0] ** 2)
            for op in eq.jump_operators[0].jump_operators:
                rates_into_degenerate = rates_into_degenerate + (np.abs(states.conj().T @ op @ states) ** 2).flatten()
            rates_into_degenerate = np.reshape(rates_into_degenerate, (energies.shape[0], energies.shape[0]))
            rates_into_degenerate = rates_into_degenerate[:, 0].flatten().real

            rates_into_degenerate = rates_into_degenerate[1:graph.degeneracy]
            rates_into_degenerate = np.sum(rates_into_degenerate)

            overlap = overlap.real - rates_into_degenerate
        return overlap.real
예제 #2
0
def compute_first_beta_order(eq: LindbladMasterEquation, schedule):
    dt = .001

    def energy_difference(t):
        schedule(t, 1)
        eigvals, eigvecs = SchrodingerEquation(
            hamiltonians=eq.hamiltonians).eig()
        return eigvals[-1] - eigvals[0]

    def integrated_phase_factor(t):
        return scipy.integrate.quad(energy_difference,
                                    0,
                                    t,
                                    epsrel=1e-7,
                                    epsabs=1e-7)[0]

    phase = integrated_phase_factor(1)
    # Compute matrix element at the very beginning and end
    schedule(1 - dt, 1)
    eigvals, eigvecs = SchrodingerEquation(hamiltonians=eq.hamiltonians).eig()
    schedule(1 - 2 * dt, 1)
    eigvals_past, eigvecs_past = SchrodingerEquation(
        hamiltonians=eq.hamiltonians).eig()
    # ensure that the first eigenvalue is positive
    if eigvecs[0][0] <= 0:
        eigvecs[0] = eigvecs[0] * -1

    if eigvecs_past[0][0] <= 0:
        eigvecs_past[0] = eigvecs_past[0] * -1

    if eigvecs[-1][0] <= 0:
        eigvecs[-1] = eigvecs[-1] * -1

    if eigvecs_past[-1][0] <= 0:
        eigvecs_past[-1] = eigvecs_past[-1] * -1

    res_end = (np.vdot(eigvecs[-1], (eigvecs[0] - eigvecs_past[0]) / dt) /
               (eigvals[0] - eigvals[-1]))
    schedule(2 * dt, 1)
    eigvals, eigvecs = SchrodingerEquation(hamiltonians=eq.hamiltonians).eig()
    schedule(dt, 1)
    eigvals_past, eigvecs_past = SchrodingerEquation(
        hamiltonians=eq.hamiltonians).eig()
    # ensure that the first eigenvalue is positive
    if eigvecs[0][0] <= 0:
        eigvecs[0] = eigvecs[0] * -1

    if eigvecs_past[0][0] <= 0:
        eigvecs_past[0] = eigvecs_past[0] * -1

    if eigvecs[-1][0] <= 0:
        eigvecs[-1] = eigvecs[-1] * -1

    if eigvecs_past[-1][0] <= 0:
        eigvecs_past[-1] = eigvecs_past[-1] * -1

    res_beginning = (np.vdot(eigvecs[-1],
                             (eigvecs[0] - eigvecs_past[0]) / dt) /
                     (eigvals[0] - eigvals[-1]))
    print(res_end**2 + res_beginning**2)
예제 #3
0
파일: adiabatic.py 프로젝트: gharib85/qsim
    def spectrum_vs_time(self, time, schedule, k=2, num=None, plot=False, which='S', hamiltonian=True):
        """Solves for the small (S) or large (L) energy sector."""
        if num is None:
            num = self._num_from_time(time)
        times = np.linspace(0, time, num=num)
        if not hamiltonian and (self.noise_model is None or self.noise_model is 'monte_carlo'):
            print('No noise models found. Finding Hamiltonian spectrum')
            hamiltonian = True
        if self.noise_model is None or self.noise_model is 'monte_carlo' or hamiltonian:
            # Initialize Schrodinger equation
            schrodinger_equation = SchrodingerEquation(hamiltonians=self.hamiltonian)
            eigvals = np.zeros((len(times), k), dtype=np.float64)
            for i in range(len(times)):
                schedule(times[i], time)
                eigval, eigvec = schrodinger_equation.eig(which=which, k=k)
                if which == 'S':
                    eigvals[i] = eigval[0:k]
                elif which == 'L':
                    eigvals[i] = eigval[len(eigval)-k-1:-1]
            if plot:
                plotted_eigvals = np.swapaxes(eigvals, 0, 1)
                for i in range(k):
                    plt.scatter(times, plotted_eigvals[i], color='teal')
                plt.ylabel('Energy')
                plt.xlabel('Time')
                plt.show()
        else:
            eigvals = np.zeros((len(times), self.cost_hamiltonian.shape[0], self.cost_hamiltonian.shape[0]),
                               dtype=np.complex128)
            raise NotImplementedError

        return eigvals
예제 #4
0
 def evolve(t):
     # Generate a mapping from a time to an index
     schedule(t, 1)
     if not full_output:
         if degeneracy == 1:
             ground_energy, ground_state = SchrodingerEquation(
                 hamiltonians=eq.hamiltonians).ground_state()
             overlap = 0
             for op in eq.jump_operators[0].jump_operators:
                 overlap = overlap - (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] + \
                           (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0]
         else:
             # Solve for the k lowest eigenvalues, where k=degeneracy
             energies, states = SchrodingerEquation(
                 hamiltonians=eq.hamiltonians).eig(k=degeneracy)
             states = states.T
             ground_state = states[:, 0]
             overlap = np.zeros(energies.shape[0]**2)
             diag = np.zeros(energies.shape[0])
             for op in eq.jump_operators[0].jump_operators:
                 overlap = overlap + (np.abs(states.conj().T @ op @ states)
                                      **2).flatten()
                 diag = diag - ground_state.conj().T @ op.conj(
                 ).T @ op @ ground_state
             overlap = overlap + np.diag(diag).flatten()
     else:
         energies, states = SchrodingerEquation(
             hamiltonians=eq.hamiltonians).eig(k='all')
         states = states.T
         overlap = np.zeros(energies.shape[0]**2)
         for op in eq.jump_operators[0].jump_operators:
             overlap = overlap + (np.abs(states.conj().T @ op @ states)**
                                  2).flatten()
     return overlap.real
예제 #5
0
def jump_rate_scaling():
    graph = Graph(nx.star_graph(n=4))  # line_graph(n=3)
    energy = 1
    phis = np.arange(.001, .01, .001)
    rates = np.zeros(len(phis))
    rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph,
                                                          IS_subspace=True,
                                                          code=qubit)
    print(rydberg_hamiltonian_cost.hamiltonian)
    for d in range(len(phis)):
        print(d)
        laser = EffectiveOperatorHamiltonian(omega_g=np.cos(phis[d]),
                                             omega_r=np.sin(phis[d]),
                                             energies=(energy, ),
                                             graph=graph)
        dissipation = EffectiveOperatorDissipation(omega_g=np.cos(phis[d]),
                                                   omega_r=np.sin(phis[d]),
                                                   rates=(energy, ),
                                                   graph=graph)
        # Find the dressed states
        simulation = SchrodingerEquation(hamiltonians=[laser])
        eigval, eigvec = simulation.eig()
        eigval = [
            rydberg_hamiltonian_cost.approximation_ratio(
                State(eigvec[i].T, is_ket=True, graph=graph, IS_subspace=True))
            for i in range(eigval.shape[0])
        ]
        print(eigval)
        optimal_eigval_index = np.argmax(eigval)
        optimal_eigval = eigvec[optimal_eigval_index]
        rate = 0
        for i in range(graph.n):
            # Compute the decay rate of the MIS into other states
            for j in range(eigvec.shape[0]):
                if j != optimal_eigval_index:
                    rate += np.abs(eigvec[j] @ dissipation.jump_operators[i]
                                   @ optimal_eigval.T)**2
        rates[d] = rate
    fit = np.polyfit(np.log(phis), np.log(rates), deg=1)

    plt.scatter(np.log(phis), np.log(rates), color='teal')
    plt.plot(np.log(phis),
             fit[0] * np.log(phis) + fit[1],
             color='k',
             label=r'$y=$' + str(np.round(fit[0], decimals=2)) + r'$x+$' +
             str(np.round(fit[1], decimals=2)))
    plt.legend()
    plt.xlabel(r'$\log(\phi)$')
    plt.ylabel(r'$\log(\rm{rate})$')
    plt.show()
예제 #6
0
파일: sk_gap.py 프로젝트: maddiecain/qsim
def find_gap(graph, use_Z2_symmetry=True):
    # Compute the number of ground states and first excited states
    cost = HamiltonianMaxCut(graph, cost_function=False, use_Z2_symmetry=use_Z2_symmetry)
    # Generate a dummy graph with one fewer nodes
    # Cut cost and driver hamiltonian in half to account for Z2 symmetry
    if use_Z2_symmetry:
        driver = HamiltonianDriver(graph=Graph(nx.complete_graph(graph.n - 1)))
        driver.hamiltonian
        row = list(range(2 ** (graph.n - 1)))
        column = list(range(2 ** (graph.n - 1)))
        column.reverse()
        driver._hamiltonian = driver._hamiltonian + (-1) ** graph.n * sparse.csr_matrix(
            (np.ones(2 ** (graph.n - 1)), (row, column)))
    else:
        driver = HamiltonianDriver(graph=Graph(nx.complete_graph(graph.n)))
    n_ground = len(ground_states(cost.hamiltonian))
    times = np.arange(0, 1, .01)

    def schedule(t):
        cost.energies = (t,)
        driver.energies = (t - 1,)

    min_gap = np.inf
    for i in range(len(times)):
        schedule(times[i])
        eigvals = SchrodingerEquation(hamiltonians=[cost, driver]).eig(k=n_ground + 1, return_eigenvectors=False)
        eigvals = np.flip(eigvals)
        if eigvals[-1] - eigvals[0] < min_gap:
            min_gap = eigvals[-1] - eigvals[0]
    return min_gap, n_ground
예제 #7
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
예제 #8
0
def rate_vs_eigenenergy(times, graph=line_graph(n=2), which='S'):
    """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus
    the final eigenenergy"""
    bad = np.arange(0, 2**graph.n, 1)
    if which == 'S':
        index = 0
    elif which == 'L':
        index = -1
    else:
        index = which
    bad = np.delete(bad, index)
    full_rates = np.zeros(len(bad))

    # Good is a list of good eigenvalues
    # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good'
    def schedule(t, tf):
        phi = (tf - t) / tf * np.pi / 2
        x.energies = (np.sin(phi)**2, )

    x = hamiltonian.HamiltonianDriver(graph=graph,
                                      IS_subspace=False,
                                      energies=(1, ))
    zz = hamiltonian.HamiltonianMaxCut(graph,
                                       cost_function=False,
                                       energies=(1 / 2, ))
    #dissipation = lindblad_operators.SpontaneousEmission(graph=graph, rates=(1,))
    eq = SchrodingerEquation(hamiltonians=[x, zz])

    def compute_rate():
        # Construct the first order transition matrix
        energies, states = eq.eig(k='all')
        rates = np.zeros(len(bad))
        for j in range(graph.n):
            for i in range(len(bad)):
                rates[i] = rates[i] + (np.abs(
                    states[i].conj() @ qubit.left_multiply(
                        State(states[index].T), [j], qubit.Z))**2)[0, 0]
        # Select the relevant rates from 'good' to 'bad'
        print(rates)
        return rates

    for i in range(len(times)):
        print(times[i])
        schedule(times[i], 1)
        full_rates = full_rates + compute_rate()
        eigval, eigvec = eq.eig(k='all')
    return full_rates, eigval
예제 #9
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
예제 #10
0
파일: sk_gap.py 프로젝트: maddiecain/qsim
 def gap(t):
     t = t[0]
     if verbose:
         print('time', t)
     schedule(t)
     eigvals = SchrodingerEquation(hamiltonians=[cost, driver]).eig(k=n_ground + 1, return_eigenvectors=False)
     eigvals = np.flip(eigvals)
     if verbose:
         print('gap', eigvals[-1]-eigvals[0])
     return eigvals[-1]-eigvals[0]
예제 #11
0
    def evolve(t, part='real'):
        # Generate a mapping from a time to an index
        dt = .001
        phase = integrated_phase_factor(t)
        schedule(t, 1)
        eigvals, eigvecs = SchrodingerEquation(
            hamiltonians=eq.hamiltonians).eig()
        schedule(t - dt, 1)
        eigvals_past, eigvecs_past = SchrodingerEquation(
            hamiltonians=eq.hamiltonians).eig()
        # ensure that the first eigenvalue is positive
        if eigvecs[0][0] <= 0:
            eigvecs[0] = eigvecs[0] * -1

        if eigvecs_past[0][0] <= 0:
            eigvecs_past[0] = eigvecs_past[0] * -1

        if eigvecs[-1][0] <= 0:
            eigvecs[-1] = eigvecs[-1] * -1

        if eigvecs_past[-1][0] <= 0:
            eigvecs_past[-1] = eigvecs_past[-1] * -1
        #print(eigvecs[0]-eigvecs_past[0])
        #print(t, np.vdot(eigvecs[-1], (eigvecs[0]-eigvecs_past[0])/dt))
        if part == 'real':
            res = (np.vdot(eigvecs[-1], (eigvecs[0] - eigvecs_past[0]) / dt) *
                   np.exp(-1j * phase)).real
            if res < 0:
                print('warning: real part is negative', t, res)
                #return 0
            return res
        else:
            res = (np.vdot(eigvecs[-1], (eigvecs[0] - eigvecs_past[0]) / dt) *
                   np.exp(-1j * phase)).imag
            if res > 0:
                print('warning: complex part is positive', t, res)
                #return 0
            return res
예제 #12
0
 def evolve(t):
     # Generate a mapping from a time to an index
     print(t)
     schedule(t, 1)
     ground_energy, ground_state = SchrodingerEquation(
         hamiltonians=eq.hamiltonians).ground_state()
     overlap = 0
     for op in eq.jump_operators[0].jump_operators:
         overlap = overlap + (np.abs(
             ground_state.conj().T @ op @ ground_state)**2)[0, 0] - (
                 ground_state.conj().T @ op.conj().T @ op @ ground_state)[0,
                                                                          0]
     #print(t, overlap.real)
     return overlap.real
예제 #13
0
파일: sk_gap.py 프로젝트: maddiecain/qsim
def low_energy_subspace_at_fixed_time(graph, s,  use_Z2_symmetry=True, n_ground=None, k=None, p=2):
    # Compute the number of ground states and first excited states
    if p == 2:
        cost = HamiltonianMaxCut(graph, cost_function=False, use_Z2_symmetry=use_Z2_symmetry)
    if p != 2:
        ham = graph
        if use_Z2_symmetry:
            graph = sk_integer(int(np.log2(graph.shape[0]))+1)
        else:
            graph = sk_integer(int(np.log2(graph.shape[0])))

        cost = HamiltonianMaxCut(graph, cost_function=False, use_Z2_symmetry=use_Z2_symmetry)
        # Replace the cost Hamiltonian
        cost._diagonal_hamiltonian = ham
        if use_Z2_symmetry:
            cost._hamiltonian = sparse.csr_matrix((cost._diagonal_hamiltonian.flatten(), (np.arange(2 ** (graph.n-1)),
                                                 np.arange(2 ** (graph.n-1)))),shape=(2 ** (graph.n-1), 2 ** (graph.n-1)))
        else:
            cost._hamiltonian = sparse.csr_matrix((cost._diagonal_hamiltonian.flatten(), (np.arange(2 ** (graph.n)),
                                                 np.arange(2 ** (graph.n)))),shape=(2 ** (graph.n), 2 ** (graph.n)))
    # Generate a dummy graph with one fewer nodes
    # Cut cost and driver hamiltonian in half to account for Z2 symmetry
    if use_Z2_symmetry:
        driver = HamiltonianDriver(graph=Graph(nx.complete_graph(graph.n - 1)))
        driver.hamiltonian
        row = list(range(2 ** (graph.n - 1)))
        column = list(range(2 ** (graph.n - 1)))
        column.reverse()
        driver._hamiltonian = driver._hamiltonian + (-1) ** graph.n * sparse.csr_matrix(
            (np.ones(2 ** (graph.n - 1)), (row, column)))
    else:
        driver = HamiltonianDriver(graph=Graph(nx.complete_graph(graph.n)))
    if k is None:
        if n_ground is None:
            n_ground = len(ground_states(cost.hamiltonian))
        k=n_ground+1

    def schedule(t):
        cost.energies = (np.sqrt(np.math.factorial(p)/(2 * graph.n**(p-1))) * t,)
        driver.energies = (1 - t,)
    schedule(s)
    eigvals = SchrodingerEquation(hamiltonians=[cost, driver]).eig(k=k, return_eigenvectors=False)
    eigvals = np.flip(eigvals)
    return s, eigvals
예제 #14
0
파일: sk_gap.py 프로젝트: maddiecain/qsim
def gap_over_time(graph, verbose=False, use_Z2_symmetry=True):
    # Compute the number of ground states and first excited states
    cost = HamiltonianMaxCut(graph, cost_function=False, use_Z2_symmetry=use_Z2_symmetry)
    print(np.min(cost.hamiltonian) / graph.n ** (3 / 2))
    # Generate a dummy graph with one fewer nodes
    # Cut cost and driver hamiltonian in half to account for Z2 symmetry
    if use_Z2_symmetry:
        driver = HamiltonianDriver(graph=Graph(nx.complete_graph(graph.n - 1)))
        driver.hamiltonian
        row = list(range(2 ** (graph.n - 1)))
        column = list(range(2 ** (graph.n - 1)))
        column.reverse()
        driver._hamiltonian = driver._hamiltonian + (-1) ** graph.n * sparse.csr_matrix(
            (np.ones(2 ** (graph.n - 1)), (row, column)))
    else:
        driver = HamiltonianDriver(graph=Graph(nx.complete_graph(graph.n)))
    if verbose:
        print(ground_states(cost.hamiltonian))
    n_ground = len(ground_states(cost.hamiltonian))
    # print(driver.hamiltonian.todense())
    # print(np.linalg.eigh(driver.hamiltonian.todense()))
    if verbose:
        print('degeneracy ', n_ground)
    times = np.arange(0, 1, .01)

    def schedule(t):
        cost.energies = (1 / np.sqrt(graph.n) * t,)
        driver.energies = (1 - t,)

    all_eigvals = np.zeros((len(times), n_ground + 1))
    for i in range(len(times)):
        if verbose:
            print(times[i])
        schedule(times[i])
        eigvals = SchrodingerEquation(hamiltonians=[cost, driver]).eig(k=n_ground + 1, return_eigenvectors=False)
        eigvals = np.flip(eigvals)
        all_eigvals[i] = eigvals
    for i in range(n_ground + 1):
        plt.scatter(times, all_eigvals[:, i], color='blue', s=2)
    if verbose:
        print(all_eigvals)
    plt.xlabel(r'normalized time $s$')
    plt.ylabel(r'energy')
    plt.show()
예제 #15
0
    def evolve(t):
        # Generate a mapping from a time to an index
        def find_nearest_index(array, value):
            array = np.asarray(array)
            idx = (np.abs(array - value)).argmin()
            return idx

        index = find_nearest_index(times, t)
        schedule(t, 1)
        eigenenergies, eigenbasis = SchrodingerEquation(
            hamiltonians=eq.hamiltonians).eig()
        eigenbasis = eigenbasis.T

        ops = []
        for op in eq.jump_operators[0].jump_operators:
            ops.append(eigenbasis.conj().T @ op @ eigenbasis)

        temp = np.zeros((dim, dim))
        for op in ops:
            temp = temp + op @ rhos[index] @ op.conj().T - 1 / 2 * (
                op.conj().T @ op @ rhos[index] +
                rhos[index] @ op.conj().T @ op)
        return np.diag(np.multiply(temp, np.identity(dim)))
예제 #16
0
파일: adiabatic.py 프로젝트: gharib85/qsim
    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
예제 #17
0
    def run_stochastic_wavefunction_solver(self,
                                           s,
                                           t0,
                                           tf,
                                           num=50,
                                           schedule=lambda t: None,
                                           times=None,
                                           full_output=True,
                                           method='trotterize',
                                           verbose=False,
                                           iterations=None):
        if iterations is None:
            iterations = 1
        # Compute probability that we have a jump
        # For the stochastic solver, we have to return a times dictionary
        assert s.is_ket
        # Save state properties
        is_ket = s.is_ket
        code = s.code
        IS_subspace = s.IS_subspace
        state_shape = s.shape
        graph = s.graph

        num_jumps = []
        jump_times = []
        jump_indices = []

        if times is None and (method == 'odeint' or method == 'trotterize'):
            times = np.linspace(0, 1, num=int(num)) * (tf - t0) + t0
        if not (method == 'odeint' or method == 'trotterize'):
            raise NotImplementedError

        schrodinger_equation = SchrodingerEquation(
            hamiltonians=self.hamiltonians + self.jump_operators)

        def f(t, state):
            if method == 'odeint':
                t, state = state, t
            if method != 'odeint':
                state = np.reshape(np.expand_dims(state, axis=0), state_shape)
            state = State(state,
                          is_ket=is_ket,
                          code=code,
                          IS_subspace=IS_subspace)
            return np.asarray(
                schrodinger_equation.evolution_generator(state)).flatten()

        assert len(times) > 1
        if full_output:
            outputs = np.zeros(
                (iterations, len(times), s.shape[0], s.shape[1]),
                dtype=np.complex128)
        else:
            outputs = np.zeros((iterations, s.shape[0], s.shape[1]),
                               dtype=np.complex128)
        dt = times[1] - times[0]
        for k in range(iterations):
            jump_time = []
            jump_indices_iter = []
            num_jump = 0
            out = s.copy()
            if verbose:
                print('Iteration', k)
            for (j, time) in zip(range(times.shape[0]), times):
                # Update energies
                schedule(time)
                for i in range(len(self.jump_operators)):
                    if i == 0:
                        jumped_states, jump_probabilities = self.jump_operators[
                            i].jump_rate(
                                out, list(range(out.number_physical_qudits)))
                        jump_probabilities = jump_probabilities * dt
                    elif i > 0:
                        js, jp = self.jump_operators[i].jump_rate(
                            out, list(range(out.number_physical_qudits)))
                        jump_probabilities = np.concatenate(
                            [jump_probabilities, jp * dt])
                        jumped_states = np.concatenate([jumped_states, js])
                if len(self.jump_operators) == 0:
                    jump_probability = 0
                else:
                    jump_probability = np.sum(jump_probabilities)
                if np.random.uniform() < jump_probability and len(
                        self.jump_operators) != 0:
                    # Then we should do a jump
                    num_jump += 1
                    jump_time.append(time)
                    if verbose:
                        print('Jumped with probability', jump_probability,
                              'at time', time)
                    jump_index = np.random.choice(
                        list(range(len(jump_probabilities))),
                        p=jump_probabilities / np.sum(jump_probabilities))
                    jump_indices_iter.append(jump_index)
                    out = State(jumped_states[jump_index, ...] *
                                np.sqrt(dt / jump_probabilities[jump_index]),
                                is_ket=is_ket,
                                code=code,
                                IS_subspace=IS_subspace,
                                graph=graph)
                    # Normalization factor
                else:
                    state_asarray = np.asarray(out)
                    if method == 'odeint':
                        z = odeintw(f,
                                    state_asarray, [0, dt],
                                    full_output=False)
                        out = State(z[-1],
                                    code=code,
                                    IS_subspace=IS_subspace,
                                    is_ket=is_ket,
                                    graph=graph)

                    else:
                        for hamiltonian in self.hamiltonians:
                            out = hamiltonian.evolve(out, dt)

                        for jump_operator in self.jump_operators:
                            if isinstance(jump_operator, LindbladJumpOperator):
                                # Non-hermitian evolve
                                out = jump_operator.nh_evolve(out, dt)
                            elif isinstance(jump_operator, QuantumChannel):
                                out = jump_operator.evolve(out, dt)
                        out = State(out,
                                    code=code,
                                    IS_subspace=IS_subspace,
                                    is_ket=is_ket,
                                    graph=graph)

                    # Normalize the output
                    out = out / np.linalg.norm(out)
                    # We don't do np.sqrt(1 - jump_probability) because it is only a first order expansion,
                    # and is often inaccurate. Things will quickly diverge if the state is not normalized
                if full_output:
                    outputs[k, j, ...] = out
            jump_times.append(jump_time)
            jump_indices.append(jump_indices_iter)
            num_jumps.append(num_jump)
            if not full_output:
                outputs[k, ...] = out

        return outputs, {
            't': times,
            'jump_times': jump_times,
            'num_jumps': num_jumps,
            'jump_indices': jump_indices
        }
예제 #18
0
 def energy_difference(t):
     schedule(t, 1)
     eigvals, eigvecs = SchrodingerEquation(
         hamiltonians=eq.hamiltonians).eig()
     return eigvals[-1] - eigvals[0]
예제 #19
0
def optimize_schedule(times, bad, graph=line_graph(n=2), initial_guesses=10):
    # Good is a list of good eigenvalues
    # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good'
    def schedule_hybrid(t, tf):
        phi = (tf - t) / tf * np.pi / 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)

    laser = EffectiveOperatorHamiltonian(graph=graph,
                                         IS_subspace=True,
                                         energies=(1, ),
                                         omega_g=np.cos(np.pi / 4),
                                         omega_r=np.sin(np.pi / 4))
    energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True,
                                                      graph=graph,
                                                      energies=(2.5, ),
                                                      index=0)
    dissipation = EffectiveOperatorDissipation(graph=graph,
                                               omega_r=1,
                                               omega_g=1,
                                               rates=(1, ))
    schedule = schedule_hybrid
    eq = SchrodingerEquation(hamiltonians=[laser, energy_shift])

    def optimize_delta_r(delta_r):
        delta_r = delta_r[0]
        energy_shift.energies = (delta_r, )
        if bad == 'other':
            ground_energy, ground_state = eq.ground_state()
            overlap = 0
            for op in dissipation.jump_operators:
                overlap = overlap + (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] - \
                          (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0]
            return overlap.real
        else:
            # Construct the first order transition matrix
            energies, states = eq.eig(k='all')
            states = states.T
            rates = np.zeros(energies.shape[0]**2)
            for op in dissipation.jump_operators:
                rates = rates + (np.abs(states.conj().T @ op @ states)**
                                 2).flatten()
            # Select the relevant rates from 'good' to 'bad'
            rates = np.reshape(
                rates.real,
                (int(np.sqrt(rates.shape[0])), int(np.sqrt(rates.shape[0]))))
            rate = 0
            for i in bad:
                rate += rates[i, 0]
            # print(time, rates, rate, delta_r)
            return rate

    delta_rs = []
    rates = []
    for time in times:
        print(time)
        schedule(time, 1)
        min_rate = np.inf
        min_delta_r = np.inf
        for i in range(initial_guesses):
            bounds = [-3, 3]
            rand = np.random.uniform(bounds[0], bounds[1], 1)
            delta_r = scipy.optimize.minimize(lambda dr: optimize_delta_r(dr),
                                              rand,
                                              bounds=[bounds])
            print(time, delta_r.x[0], delta_r.fun)
            if delta_r.fun < min_rate:
                min_delta_r = delta_r.x[0]
                min_rate = delta_r.fun
        delta_rs.append(min_delta_r)
        rates.append(min_rate)
    return delta_rs, rates
예제 #20
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
예제 #21
0
    diag_energy = adjacent_energy/8
    second_nearest_energy = adjacent_energy/64
    for i in range(layout.shape[0] - 1):
        for j in range(layout.shape[1] - 1):
            if layout[i, j] == 1:
                # There is a spin here
                pass


#imperfect_blockade_performance()


graph = line_graph(n=3, return_mis=False)
phi = np.pi/2
laser = EffectiveOperatorHamiltonian(omega_g=np.cos(phi), omega_r=np.sin(phi), graph=graph)
eq = SchrodingerEquation(hamiltonians=[laser])

state = State(np.ones((5, 1), dtype=np.complex128)/np.sqrt(5))
print(np.round(eq.eig(k='all')[1], decimals=3))

def performance_vs_alpha():
    # alpha = gamma * omega^2/(delta^2 T)
    graph = line_graph(n=3)
    gammas = np.array([1, 5, 10])
    times = np.array([1, 5, 10])
    deltas = np.array([20, 30])
    omegas = np.array([1, 5, 10])
    for (g, d, o) in zip(gammas, deltas, omegas):
        # Find the performance vs alpha
        laser = EffectiveOperatorHamiltonian(graph=graph)
        dissipation = EffectiveOperatorDissipation(graph=graph)
예제 #22
0
def rate_vs_eigenenergy(times,
                        graph=line_graph(n=2),
                        mode='hybrid',
                        which='S'):
    """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus
    the final eigenenergy"""
    if which == 'S':
        index = 0
    elif which == 'L':
        index = -1
    else:
        index = which

    # Good is a list of good eigenvalues
    # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good'
    def schedule_hybrid(t, tf):
        phi = (tf - t) / tf * np.pi / 2
        energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), )
        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_reit(t, tf):
        phi = (tf - t) / tf * np.pi / 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):
        phi = (tf - t) / tf * np.pi / 2
        energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), )
        laser.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))
        laser.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))
        dissipation.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))
        dissipation.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))

    laser = EffectiveOperatorHamiltonian(graph=graph,
                                         IS_subspace=True,
                                         energies=(1, ),
                                         omega_g=np.cos(np.pi / 4),
                                         omega_r=np.sin(np.pi / 4))
    energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True,
                                                      graph=graph,
                                                      energies=(2.5, ),
                                                      index=0)
    dissipation = EffectiveOperatorDissipation(graph=graph,
                                               omega_r=1,
                                               omega_g=1,
                                               rates=(1, ))
    if mode == 'hybrid':
        schedule = schedule_hybrid
    elif mode == 'adiabatic':
        schedule = schedule_adiabatic
    elif mode == 'reit':
        schedule = schedule_reit
    if mode != 'reit':
        eq = SchrodingerEquation(hamiltonians=[laser, energy_shift])
    else:
        eq = SchrodingerEquation(hamiltonians=[laser])

    def compute_rate():
        # Construct the first order transition matrix
        global full_rates
        energies, states = eq.eig(k='all')
        states = states.T
        rates = np.zeros(energies.shape[0]**2)
        for op in dissipation.jump_operators:
            rates = rates + (np.abs(states.conj().T @ op @ states)**
                             2).flatten()
        # Select the relevant rates from 'good' to 'bad'

        rates = np.reshape(
            rates.real,
            (graph.num_independent_sets, graph.num_independent_sets))
        return rates[:, index].flatten()

    for i in range(len(times)):
        print(times[i])
        schedule(times[i], 1)
        full_rates = compute_rate()
        eigval, eigvec = eq.eig(k='all')
    return full_rates, eigval
예제 #23
0
def dissipation_over_time(times,
                          delta_rs,
                          graph=line_graph(n=2),
                          mode='hybrid',
                          which='S'):

    rates = np.zeros((len(delta_rs), len(times)))
    if which == 'S':
        index = 0
    if which == 'L':
        index = graph.num_independent_sets - 1

    optimal_energy = graph.independent_sets[index][1]
    degeneracy = 0
    bad = []
    for IS in graph.independent_sets:
        if graph.independent_sets[IS][1] == optimal_energy:
            degeneracy += 1
        else:
            bad.append(IS)
    if degeneracy == 1:
        bad = 'other'
    # Good is a list of good eigenvalues
    # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good'
    def schedule_hybrid(t, tf):
        phi = (tf - t) / tf * np.pi / 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):
        phi = (tf - t) / tf * np.pi / 2
        laser.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))
        laser.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))
        dissipation.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))
        dissipation.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi)))

    laser = EffectiveOperatorHamiltonian(graph=graph,
                                         IS_subspace=True,
                                         energies=(1, ),
                                         omega_g=np.cos(np.pi / 4),
                                         omega_r=np.sin(np.pi / 4))
    energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True,
                                                      graph=graph,
                                                      energies=(2.5, ),
                                                      index=0)
    dissipation = EffectiveOperatorDissipation(graph=graph,
                                               omega_r=1,
                                               omega_g=1,
                                               rates=(1, ))
    if mode == 'hybrid':
        schedule = schedule_hybrid
    elif mode == 'adiabatic':
        schedule = schedule_adiabatic
    eq = SchrodingerEquation(hamiltonians=[laser, energy_shift])

    def compute_rate(delta_r):
        energy_shift.energies = (delta_r, )
        if bad == 'other' and which == 'S':
            ground_energy, ground_state = eq.ground_state()
            overlap = 0
            for op in dissipation.jump_operators:
                overlap = overlap - (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] + \
                          (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0]
            return overlap.real
        else:
            # Construct the first order transition matrix
            energies, states = eq.eig(k='all')
            states = states.T
            rates = np.zeros(energies.shape[0]**2)
            for op in dissipation.jump_operators:
                rates = rates + (np.abs(states.conj().T @ op @ states)**
                                 2).flatten()
            # Select the relevant rates from 'good' to 'bad'
            rates = np.reshape(
                rates.real,
                (int(np.sqrt(rates.shape[0])), int(np.sqrt(rates.shape[0]))))
            rate = 0
            for i in bad:
                rate += rates[i, index]
            return rate

    for i in range(len(times)):
        print(times[i])
        schedule(times[i], 1)
        for j in range(len(delta_rs)):
            rates[j, i] = compute_rate(delta_rs[j])

    return rates
예제 #24
0
파일: one_atom.py 프로젝트: maddiecain/qsim
    plt.legend()
    plt.tight_layout()
    plt.show()


energies = [
    1.2679491924311228, 1.5505102572168215, 1.9999999999999991,
    2.369723378886908, 2.7797808497772705, 3.169041327665013,
    3.569285832151517, 3.963676830741, 4.361224193455282, 4.757059445281552,
    5.153829596112403, 5.550087062995971, 5.946626869831041, 6.343010696247533,
    6.739480949302909, 7.135903198980722, 7.532352169228637, 7.928786237774574,
    8.325228630906286
]
#plt.scatter(range(3, 22), energies)
#plt.show()
fidelity_vs_alpha()
for i in range(0, 0):

    graph = ring_graph(i)
    laser = EffectiveOperatorHamiltonian(1,
                                         1,
                                         energies=(1, ),
                                         graph=graph,
                                         IS_subspace=True)
    #energy_shift = hamiltonian.HamiltonianEnergyShift(graph=graph, IS_subspace=True)
    eq = SchrodingerEquation(hamiltonians=[laser])
    energy, ground_state = eq.ground_state()
    print(energy)  #, np.abs(ground_state)**2)
    """plt.scatter(np.arange(len(ground_state)), ground_state)
    plt.show()"""
예제 #25
0
파일: one_atom.py 프로젝트: maddiecain/qsim
def fidelity_vs_alpha():
    graph = line_graph(5)
    omega = 100
    T = 100
    delta_e = 1000
    beta = delta_e / (omega**2 * T)
    print('beta = ' + str(beta))
    gammas = 10**np.linspace(1.75, 3.25, 3)
    print(gammas * omega**2 * T / delta_e**2)
    dissipation = EffectiveOperatorDissipation(0,
                                               0,
                                               graph=graph,
                                               IS_subspace=True,
                                               rates=(1 / delta_e**2, ))
    laser = EffectiveOperatorHamiltonian(0,
                                         0,
                                         energies=(1 / delta_e, ),
                                         graph=graph,
                                         IS_subspace=True)
    energy_shift = hamiltonian.HamiltonianEnergyShift(graph=graph,
                                                      IS_subspace=True)

    def schedule_exp_fixed(t, tf=T):
        x = t / tf * np.pi / 2
        amplitude = np.abs(np.cos(x) * np.sin(x))
        # Now we need to figure out what the driver strengths should be for STIRAP
        omega_g = np.sin(x) * omega
        omega_r = np.cos(x) * omega
        offset = omega_r**2 - omega_g**2
        # Now, choose the opposite of the STIRAP sequence
        energy_shift.energies = (offset / 1000, )
        laser.omega_g = np.sqrt(amplitude) * omega
        laser.omega_r = np.sqrt(amplitude) * omega
        dissipation.omega_g = np.sqrt(amplitude) * omega
        dissipation.omega_r = np.sqrt(amplitude) * omega

    def schedule_reit(t, tf=T):
        x = t / tf * np.pi / 2
        omega_g = np.sin(x) * omega
        omega_r = np.cos(x) * omega
        energy_shift.energies = (0, )
        laser.omega_g = omega_g
        laser.omega_r = omega_r
        dissipation.omega_g = omega_g
        dissipation.omega_r = omega_r

    eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift],
                                jump_operators=[dissipation])
    nonoise_eq = SchrodingerEquation(hamiltonians=[laser, energy_shift])
    state = State(np.array([[0, 0], [0, 1]], dtype=np.complex128),
                  IS_subspace=True,
                  graph=graph,
                  is_ket=False)
    state = State(np.array([[0, 0, 0], [0, 0, 0], [0, 0, 1]],
                           dtype=np.complex128),
                  IS_subspace=True,
                  graph=graph,
                  is_ket=False)
    state = State(np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0],
                            [0, 0, 0, 0, 0], [0, 0, 0, 0, 1]],
                           dtype=np.complex128),
                  IS_subspace=True,
                  graph=graph,
                  is_ket=False)
    state = State(np.zeros((13, 13), dtype=np.complex128),
                  IS_subspace=True,
                  graph=graph,
                  is_ket=False)
    state[-1, -1] = 1
    # nonoise_state = State(np.array([[0], [0], [1]], dtype=np.complex128), IS_subspace=True, graph=graph, is_ket=True)
    # print(np.abs(nonoise_eq.run_ode_solver(nonoise_state, 0, T, num=500, schedule=schedule_exp_fixed, method='odeint')[0][-1])**2)
    for a in [1]:
        delta_e = a * 1000
        laser.energies = (1 / delta_e, )
        fidelities = []
        ars = []
        for i in range(len(gammas)):
            dissipation.rates = (gammas[i] / delta_e**2, )
            states = eq.run_ode_solver(state,
                                       0,
                                       T,
                                       num=50,
                                       schedule=schedule_reit,
                                       make_valid_state=False,
                                       method='odeint')
            times = states[1]['t']
            states = states[0]
            """print(gammas[i], i)
            for j in range(len(times)):
                for op in dissipation.jump_operators:
                    print(np.trace(op.conj().T@op@states[j])-np.abs(np.trace(op@states[j]))**2)"""
            """print(times[25])
            schedule_exp_fixed(times[25], tf=T)
            eigvals, eigvecs = nonoise_eq.eig(k='all')
            print(eigvals)
            print(eigvecs.conj()@states[25]@eigvecs.T)"""
            final_state = states[-1]
            #print(final_state)
            #print(final_state[0, 0], np.trace(final_state))
            ar = (final_state[0, 0] + 2 / 3 *
                  (final_state[1, 1] + final_state[2, 2] + final_state[3, 3] +
                   final_state[6, 6] + final_state[5, 5] + final_state[8, 8]) +
                  1 / 2 *
                  (final_state[7, 7] + final_state[4, 4] + final_state[9, 9] +
                   final_state[10, 10] + final_state[11, 11]))
            print(ar)
            print(final_state[0, 0])
            print(final_state.diagonal())
            ars.append(ar)
            fidelities.append(final_state[0, 0])
        fidelities = np.array(fidelities)
        ars = np.array(ars)
        plt.loglog()
        plt.ylabel(r'$1-$ fidelity')
        plt.xlabel(r'$\frac{\gamma \Omega^2 T}{\delta_e^2}$')
        plt.plot(gammas * omega**2 * T / delta_e**2,
                 1 - fidelities,
                 label='fidelity')
        plt.plot(gammas * omega**2 * T / delta_e**2, 1 - ars, label='ar')
        res = np.polyfit(np.log(gammas * omega**2 * T / delta_e**2),
                         np.log(1 - fidelities), 1)
        print(res)
        #plt.plot(gammas * omega ** 2 * T / delta_e ** 2,
        #         1 - np.e ** (-gammas * omega ** 2 * T / delta_e ** 2 * 0.033875094811638556),
        #         label='bound')
        """if a == -1:

            plt.plot(gammas * omega ** 2 * T / delta_e ** 2,
                     0.28187096704733217 * gammas * omega ** 2 * T / delta_e ** 2,
                     label='first order correction')
        else:
            plt.plot(gammas * omega ** 2 * T / delta_e ** 2,
                     0.033875094811638556 * gammas * omega ** 2 * T / delta_e ** 2,
                     label='first order correction')"""

    plt.legend()
    plt.tight_layout()
    plt.show()
예제 #26
0
def alpha_correction_ar(graph=line_graph(n=2),
                        mode='hybrid',
                        angle=np.pi / 4,
                        which='S',
                        verbose=False):
    """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus
    the final eigenenergy"""
    if which == 'S':
        index = 0
    elif which == 'L':
        index = graph.num_independent_sets - 1
    else:
        index = which

    energies = []
    bad_indices = []
    target_energy = graph.independent_sets[index][1]
    degeneracy = 0
    # Compute maximum independent set size and "bad" energies
    for IS in graph.independent_sets:
        if graph.independent_sets[IS][1] != target_energy:
            energies.append(graph.independent_sets[IS][1])
            bad_indices.append(IS)
        else:
            degeneracy += 1
    energies = np.array(energies)
    energies = np.abs(target_energy - energies)

    # Good is a list of good eigenvalues
    # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good'
    def schedule_hybrid(t, tf):
        phi = (tf - t) / tf * np.pi / 2
        energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), )
        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_reit(t, tf):
        phi = (tf - t) / tf * np.pi / 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):
        phi = (tf - t) / tf * np.pi / 2
        energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), )
        laser.omega_g = np.cos(angle) * np.sin(phi) * np.cos(phi)
        laser.omega_r = np.sin(angle) * np.sin(phi) * np.cos(phi)
        dissipation.omega_g = np.cos(angle) * np.cos(phi) * np.sin(phi)
        dissipation.omega_r = np.sin(angle) * np.cos(phi) * np.sin(phi)

    laser = EffectiveOperatorHamiltonian(graph=graph,
                                         IS_subspace=True,
                                         energies=(1, ),
                                         omega_g=np.cos(np.pi / 4),
                                         omega_r=np.sin(np.pi / 4))
    energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True,
                                                      graph=graph,
                                                      energies=(2.5, ),
                                                      index=0)
    dissipation = EffectiveOperatorDissipation(graph=graph,
                                               omega_r=1,
                                               omega_g=1,
                                               rates=(1, ))
    if mode == 'hybrid':
        schedule = schedule_hybrid
    elif mode == 'adiabatic':
        schedule = schedule_adiabatic
    elif mode == 'reit':
        schedule = schedule_reit
    if mode != 'reit':
        eq = SchrodingerEquation(hamiltonians=[laser, energy_shift])
    else:
        eq = SchrodingerEquation(hamiltonians=[laser])

    def compute_rate(t):
        if verbose:
            print(t)
        schedule(t, 1)
        # Construct the first order transition matrix
        eigval, eigvec = eq.eig(k='all')
        eigvec = eigvec.T
        rates = np.zeros(eigval.shape[0]**2)
        for op in dissipation.jump_operators:
            rates = rates + ((eigvec.conj().T @ op @ eigvec)**2).flatten()
        # Select the relevant rates from 'good' to 'bad'

        rates = np.reshape(
            rates.real,
            (graph.num_independent_sets, graph.num_independent_sets))
        bad_rates = np.zeros(len(bad_indices))
        for i in range(len(bad_indices)):
            bad_rates[i] = bad_rates[i] + rates[bad_indices[i], index]
        return np.dot(bad_rates, energies)

    # Integrate to find the correction
    res, error = scipy.integrate.quad_vec(compute_rate, 1e-5, .9999)
    return res / target_energy, error