def transverse_ising_model_1d(N, J=1, g=1):  #Sum -JZ_iZ_i+1 + Sum gX_i
    """
    kh: what if N = 1?
    """
    paulistrings = []
    for i in range(N - 1):
        st = [0] * N
        st[i] = 3
        st[i + 1] = 3
        paulistrings.append(pcp.paulistring(N, st, -J))
    for i in range(N):
        st = [0] * N
        st[i] = 1
        paulistrings.append(pcp.paulistring(N, st, g))
    return Hamiltonian(N, paulistrings)
def generate_package_of_random_hamiltonians(
        N, howmanyrandomhamiltonians, uptohowmanyterms, numpyseed,
        maximumbeta):  #Returns a list of randomly generated hamiltonians
    random_generator = np.random.default_rng(numpyseed)
    ham_list = []
    for i in range(howmanyrandomhamiltonians):
        pauliterms = []
        while len(pauliterms) < uptohowmanyterms:
            rint = random_generator.integers(low=0, high=4, size=N)
            rstring = ''
            for j in rint:
                rstring = rstring + str(j)
            if rstring not in pauliterms:
                pauliterms.append(rstring)
        #print(pauliterms)
        paulistringobjects = []
        for term in pauliterms:
            paulistringobjects.append(
                pcp.paulistring(
                    N, term,
                    list(
                        random_generator.random(uptohowmanyterms) *
                        maximumbeta)))
        ham_list.append(Hamiltonian(N, paulistringobjects))
    return ham_list
def dagger_hamiltonian(ham1):  #Returns the dagger of the hamiltonian
    newpauliclassobjs = []
    N = ham1.return_N()
    for pold in ham1.return_paulistrings():
        newpauliclassobjs.append(
            pcp.paulistring(N, pold.return_string(),
                            np.conj(pold.return_coefficient())))
    return Hamiltonian(N, newpauliclassobjs)
def heisenberg_xyz_model(N, jx=1, jy=2, jz=3):  #Sum jx X_i X_{i+1} + ...
    j_couplings = [jx, jy, jz]
    base_string = [0] * N
    paulistrings = []
    if N == 1:
        for j in range(len(j_couplings)):
            if j_couplings[j] == 0:
                continue
            term = [j + 1]
            term = pcp.paulistring(N, term, j_couplings[j])
            paulistrings.append(term)
        return Hamiltonian(N, paulistrings)
    for i in range(N - 1):
        for j in range(len(j_couplings)):
            if j_couplings[j] == 0:
                continue
            term = base_string.copy()
            term[i] = j + 1
            term[i + 1] = j + 1
            term = pcp.paulistring(N, term, j_couplings[j])
            paulistrings.append(term)
    return Hamiltonian(N, paulistrings)
예제 #5
0
def get_fidelity_results(num_qubits, ansatzlist, times,
    whatKs, hamiltonian, initial_state):
    """
    Returns a dictionary of dictionaries. The keys are the values of K that we
    are considering, the values are the dictionaries for that K value. For a
    particular K value, the corresponding dictionary is such that the keys are
    the time values, and the values are the fidelities at that particular
    time
    """
    initial_statevector = initial_state.get_statevector()
    # if qstype == 'TTQS':
    #     name = 'TTQS'
    # if qstype == 'QAS':
    #     name = 'QAS'
    # if qstype == 'CQFF':
    #     name = 'CQFF'
    collated_fidelity_vals = dict()
    for i in range(len(ansatzlist)):
        if i in whatKs:
            print('Calculating and saving fidelity for K = ' + str(i))
            ansatz = ansatzlist[i]
            result_pauli_string, result_alphas = ansatz.get_alphas()
            result_alphas = list(zip(*result_alphas)) #transpose it so that each entry is a time value 
            fidelity_vals = dict()
            for time_idx in range(len(times)):
                time = times[time_idx]
                alpha = result_alphas[time_idx]
                alpha = np.array(alpha)
                state = np.zeros(2**num_qubits) + 1j*np.zeros(2**num_qubits)
                for j in range(len(alpha)):
                    # print("I'm here", result_pauli_string[j])
                    result_pauli_string_obj = pcp.paulistring(num_qubits, result_pauli_string[j], 1)
                    # print(result_pauli_string_obj)
                    result_pauli_string_matrix = result_pauli_string_obj.get_matrixform()
                    # print("i am here", len(initial_statevector))
                    # print("i am here two", len(result_pauli_string_matrix))
                    # print("i am here three", alpha[j])
                    state += alpha[j] * result_pauli_string_matrix @initial_statevector
                
                hamiltonian_matrix = hamiltonian.to_matrixform()
                theoretical_state = expm(-1j * hamiltonian_matrix * time) @ initial_statevector
                # theoretical_state = final_results_from_classical_simulator[time_idx]
                fidelity = np.abs(np.vdot(theoretical_state, state))
                # if time == 60:
                #     print("actual_state_is", state)
                #     print("theoretical_state_is", theoretical_state)
                # fidelity_vals.append(fidelity)
                fidelity_vals[time] = fidelity
            collated_fidelity_vals[i] = fidelity_vals
    return collated_fidelity_vals
예제 #6
0
def generate_parity_operator_matform(num_qubits):
    dim = 2**num_qubits
    P_mat = np.zeros((dim, dim))
    # test_mat = np.zeros(dim)
    for i in range(dim):
        ket_bitstring = np.binary_repr(i)
        ket_bitstring = (num_qubits - len(ket_bitstring)) * "0" + ket_bitstring
        ket = np.zeros(dim)
        ket[i] = 1
        bra_bitstring = ket_bitstring[::-1]
        bra_index = int(bra_bitstring, 2)
        # print(ket_bitstring, bra_bitstring)
        bra = np.zeros(dim)
        bra[bra_index] = 1
        P_mat += np.outer(ket, bra)
    spinflips = pcp.paulistring(num_qubits, [1] * num_qubits,
                                1).get_matrixform()
    return P_mat @ spinflips
예제 #7
0
def get_data_for_fidelity(num_qubits, ansatzlist, times,whatKs, qstype, hamiltonian, initial_state):
    finaldict = {}
    finaldict['times'] = list(times.real)
    initial_statevector = initial_state.get_statevector()
    if qstype == 'TQS':
        name = 'TQS'
    if qstype == 'QAS':
        name = 'QAS'
    if qstype == 'CQFF':
        name = 'CQFF'
    for i in range(len(ansatzlist)):
        if i in whatKs:
            #print('Plotting fidelity for K = ' + str(i))
            ansatz = ansatzlist[i]
            result_pauli_string, result_alphas = ansatz.get_alphas()
            result_alphas = list(zip(*result_alphas)) #transpose it so that each entry is a time value 
            fidelity_vals = []
            for time_idx in range(len(times)):
                time = times[time_idx]
                alpha = result_alphas[time_idx]
                alpha = np.array(alpha)
                state = np.zeros(2**num_qubits) + 1j*np.zeros(2**num_qubits)
                for j in range(len(alpha)):
                    # print("I'm here", result_pauli_string[j])
                    result_pauli_string_obj = pcp.paulistring(num_qubits, result_pauli_string[j], 1)
                    # print(result_pauli_string_obj)
                    result_pauli_string_matrix = result_pauli_string_obj.get_matrixform()
                    # print("i am here", len(initial_statevector))
                    # print("i am here two", len(result_pauli_string_matrix))
                    # print("i am here three", alpha[j])
                    state += alpha[j] * result_pauli_string_matrix @initial_statevector
                
                hamiltonian_matrix = hamiltonian.to_matrixform()
                theoretical_state = expm(-1j * hamiltonian_matrix * time) @ initial_statevector
                # theoretical_state = final_results_from_classical_simulator[time_idx]
                fidelity = np.abs(np.vdot(theoretical_state, state))
                # if time == 60:
                #     print("actual_state_is", state)
                #     print("theoretical_state_is", theoretical_state)
                fidelity_vals.append(fidelity)
            lab = name + " K=" + str(i)
            #plt.plot(times, fidelity_vals, label = lab)
            finaldict[str(i)] = list(fidelity_vals)
    return finaldict
def generate_arbitary_observable(N, couplings, pauli_strings):
    """
    Here, N is the number of qubits
    Let the observable be sum_{i=1}^r beta_i P_i
    Then, couplings = [beta_1, beta_2, ..., beta_L]
    pauli_strings = [P_1, P_2,..,P_L]
    Here, P_i is any iterable, e.g a string "123", or a list [1,2,3]. Both these iterables represent the operator X_1 Y_2 Z_3
    """
    if len(couplings) != len(pauli_strings):
        raise (RuntimeError(
            "Length of couplings must match length of pauli_strings"))
    paulistring_objects = []
    for j in range(len(pauli_strings)):
        beta_j = couplings[j]
        P_j = pauli_strings[j]
        P_j_formatted = [int(i) for i in P_j]
        pauliobject = pcp.paulistring(N, P_j_formatted, beta_j)
        paulistring_objects.append(pauliobject)
    return Observable(N, paulistring_objects)
def generate_arbitary_hamiltonian(N, couplings, pauli_strings):
    """
    Here, N is the number of qubits
    Let the Hamiltonian be sum_{i=1}^r beta_i P_i
    Then, couplings = [beta_1, beta_2, ..., beta_L]
    pauli_strings = [P_1, P_2,..,P_L]
    Here, P_i is any iterable, e.g a string "123", or a list [1,2,3]. Both these iterables represent the operator X_1 Y_2 Z_3
    
    EXAMPLE: If we have a 4 qubit system and I want to implement the hamiltonian H = 0.6*(XXII) + 0.4*(XZIY), the hamiltonian will be generated with this:
    
    generate_arbitrary_hamiltonian(4,[0.6,0.4],["1100","1302"])
    
    """
    if len(couplings) != len(pauli_strings):
        raise (RuntimeError(
            "Length of couplings must match length of pauli_strings"))
    paulistring_objects = []
    for j in range(len(pauli_strings)):
        beta_j = couplings[j]
        P_j = pauli_strings[j]
        P_j_formatted = [int(i) for i in P_j]
        pauliobject = pcp.paulistring(N, P_j_formatted, beta_j)
        paulistring_objects.append(pauliobject)
    return Hamiltonian(N, paulistring_objects)
def gen_next_ansatz(anz,
                    H,
                    N,
                    method="no_processing",
                    pruning_condition=0.1,
                    num_new_to_add=5):
    if method == 'no_processing':
        newmomentstrings = []
        for mom in anz.moments:
            newmomentstrings.append(mom.paulistring.return_string())
        for mom in anz.moments:
            for ham in H.return_paulistrings():
                newpauli = pcp.pauli_combine(mom.paulistring, ham)
                if newpauli.return_string() not in newmomentstrings:
                    newmomentstrings.append(
                        newpauli.return_string()
                    )  #This is the string that is [0,1,2,1,1,2,...] ect, NOT the paulistring class
        #print for debugging purposes
        print("there are " + str(len(newmomentstrings)) + " states in CSk")
        newmoment = []
        for i in newmomentstrings:
            newmoment.append(moment(N, paulistring(
                N, i, 1)))  #Appending the paulistring class objects
    if method == 'random_selection_new':
        oldmomentstrings = []
        for mom in anz.moments:
            oldmomentstrings.append(mom.paulistring.return_string())
        newmomentstrings = []
        for mom in anz.moments:
            for ham in H.return_paulistrings():
                newpauli = pcp.pauli_combine(mom.paulistring, ham)
                if newpauli.return_string(
                ) not in oldmomentstrings and newpauli.return_string(
                ) not in newmomentstrings:
                    newmomentstrings.append(
                        newpauli.return_string()
                    )  #This is the string that is [0,1,2,1,1,2,...] ect, NOT the paulistring class
        newmoment = []
        for i in oldmomentstrings:
            newmoment.append(moment(N, paulistring(
                N, i, 1)))  #Appending the paulistring class objects
        if len(newmomentstrings) <= num_new_to_add:
            for i in newmomentstrings:
                newmoment.append(moment(N, paulistring(
                    N, i, 1)))  #Appending the paulistring class objects
        else:
            indicestoadd = np.random.choice(len(newmomentstrings),
                                            num_new_to_add,
                                            replace=False)
            for i in indicestoadd:
                newmoment.append(
                    moment(N, paulistring(
                        N, newmomentstrings[i],
                        1)))  #Appending the paulistring class objects
        print("there are " + str(len(newmoment)) + " states in CSk")
    if method == 'pruning':
        newmomentstrings = []
        for mom in anz.moments:
            maximum = max(mom.alphas)
            if maximum > pruning_condition:
                newmomentstrings.append(mom.paulistring.return_string())
        for mom in anz.moments:
            maximum = max(mom.alphas)
            if maximum > pruning_condition:
                for ham in H.return_paulistrings():
                    newpauli = pcp.pauli_combine(mom.paulistring, ham)
                    if newpauli.return_string() not in newmomentstrings:
                        newmomentstrings.append(
                            newpauli.return_string()
                        )  #This is the string that is [0,1,2,1,1,2,...] ect, NOT the paulistring class
        #print for debugging purposes
        print("there are " + str(len(newmomentstrings)) + " states in CSk")
        newmoment = []
        for i in newmomentstrings:
            newmoment.append(moment(N, paulistring(
                N, i, 1)))  #Appending the paulistring class objects

    return Ansatz(N, anz.K + 1, newmoment)
def initial_ansatz(N):
    initialmoment = moment(N, paulistring(N, [0] * N, 1))
    return Ansatz(N, 0, [initialmoment])