def S2Proj(Quket, Q, threshold=1e-8): """Function Perform spin-projection to QuantumState |Q> |Q'> = Ps |Q> where Ps is a spin-projection operator (non-unitary). Ps = \sum_i^ng wg[i] Ug[i] This function provides a shortcut to |Q'>, which is unreal. One actually needs to develop a quantum circuit for this (See PRR 2, 043142 (2020)). Author(s): Takashi Tsuchimochi """ spin = Quket.projection.spin s = (spin - 1) / 2 Ms = Quket.projection.Ms / 2 n_qubits = Q.get_qubit_count() state_P = QuantumState(n_qubits) state_P.multiply_coef(0) nalpha = max(Quket.projection.euler_ngrids[0], 1) nbeta = max(Quket.projection.euler_ngrids[1], 1) ngamma = max(Quket.projection.euler_ngrids[2], 1) for ialpha in range(nalpha): alpha = Quket.projection.sp_angle[0][ialpha] alpha_coef = Quket.projection.sp_weight[0][ialpha] * np.exp( 1j * alpha * Ms) for ibeta in range(nbeta): beta = Quket.projection.sp_angle[1][ibeta] beta_coef = (Quket.projection.sp_weight[1][ibeta] * Quket.projection.dmm[ibeta]) for igamma in range(ngamma): gamma = Quket.projection.sp_angle[2][igamma] gamma_coef = (Quket.projection.sp_weight[2][igamma] * np.exp(1j * gamma * Ms)) # Total Weight coef = (2 * s + 1) / (8 * np.pi) * (alpha_coef * beta_coef * gamma_coef) state_g = QuantumState(n_qubits) state_g.load(Q) circuit_Rg = QuantumCircuit(n_qubits) set_circuit_Rg(circuit_Rg, n_qubits, alpha, beta, gamma) circuit_Rg.update_quantum_state(state_g) state_g.multiply_coef(coef) state_P.add_state(state_g) # Normalize norm2 = state_P.get_squared_norm() if norm2 < threshold: error( "Norm of spin-projected state is too small!\n", "This usually means the broken-symmetry state has NO component ", "of the target spin.") state_P.normalize(norm2) # print_state(state_P,name="P|Q>",threshold=1e-6) return state_P
def sample_observable_noisy_circuit(circuit, initial_state, obs, n_circuit_sample=1000, n_sample_per_circuit=1): """ Args: circuit (:class:`qulacs.QuantumCircuit`) initial_state (:class:`qulacs.QuantumState`) obs (:class:`qulacs.Observable`) n_circuit_sample (:class:`int`): number of circuit samples n_sample (:class:`int`): number of samples per one circuit samples Return: :float: sampled expectation value of the observable Author(s): Unknown """ exp = 0 state = QuantumState(obs.get_qubit_count()) for _ in range(n_circuit_sample): state.load(initial_state) circuit.update_quantum_state(state) exp += sample_observable(state, obs, n_sample_per_circuit) exp /= n_circuit_sample return exp
def _simulate_on_qulacs( self, data: _StateAndBuffer, shape: tuple, qulacs_state: qulacs.QuantumState, qulacs_circuit: qulacs.QuantumCircuit, ) -> None: data.buffer = data.state cirq_state = np.array(data.state).flatten().astype(np.complex64) qulacs_state.load(cirq_state) qulacs_circuit.update_quantum_state(qulacs_state) data.state = qulacs_state.get_vector().reshape(shape)
def fci2qubit(norbs, nalpha, nbeta, fci_coeff): """Function Perform mapping from fci coefficients to qubit representation Args: norbs (int): number of active orbitals nalpha (int): number of alpha electrons nbeta (int): number of beta electrons fci_coeff (ndarray): FCI Coefficients in a (NDetA, NDetB) array with NDetA = Choose(norbs, nalpha) NDetB = Choose(norbs, nbeta) """ #printmat(fci_coeff) NDetA = Binomial(norbs, nalpha) NDetB = Binomial(norbs, nbeta) if NDetA is not fci_coeff.shape[0] or NDetB is not fci_coeff.shape[1]: error(f"NDetA = {NDetA} NDetB = {NDetB} " f"fci_coeff = {fci_coeff.shape}" f"Wrong dimensions fci_coeff in fci2qubit") listA = list(combinations(range(norbs), nalpha)) listB = list(combinations(range(norbs), nbeta)) for isort in range(nalpha): listA = sorted(listA, key=itemgetter(isort)) for isort in range(nbeta): listB = sorted(listB, key=itemgetter(isort)) j = 0 n_qubits = norbs * 2 opt = f"0{n_qubits}b" vec = np.zeros(2**n_qubits) for ib in range(NDetB): occB = np.array([n * 2 + 1 for n in listB[ib]]) for ia in range(NDetA): occA = np.array([n * 2 for n in listA[ia]]) #prints("Det {} {}".format(ia,ib), " occA ",occA, ' occB ',occB) k = np.sum(2**occA) + np.sum(2**occB) vec[k] = fci_coeff[ia, ib] if ia <= ib else -fci_coeff[ia, ib] #if abs(fci_coeff[ia, ib]) > 1e-4: # prints(f" Det# {j+1}: ", end=""); # prints(f"| {format(k, opt)} > : {fci_coeff[ia, ib]}") #j += 1 fci_state = QuantumState(n_qubits) fci_state.load(vec) return fci_state
def sample_observable(state, obs, n_sample): """Function Args: state (qulacs.QuantumState): obs (qulacs.Observable) n_sample (int): number of samples for each observable Return: :float: sampled expectation value of the observable Author(s): Takashi Tsuchimochi """ n_term = obs.get_term_count() n_qubits = obs.get_qubit_count() exp = 0 buf_state = QuantumState(n_qubits) for i in range(n_term): pauli_term = obs.get_term(i) coef = pauli_term.get_coef() pauli_id = pauli_term.get_pauli_id_list() pauli_index = pauli_term.get_index_list() if len(pauli_id) == 0: # means identity exp += coef continue buf_state.load(state) measurement_circuit = QuantumCircuit(n_qubits) mask = "".join(["1" if n_qubits - 1 - k in pauli_index else "0" for k in range(n_qubits)]) for single_pauli, index in zip(pauli_id, pauli_index): if single_pauli == 1: measurement_circuit.add_H_gate(index) elif single_pauli == 2: measurement_circuit.add_Sdag_gate(index) measurement_circuit.add_H_gate(index) measurement_circuit.update_quantum_state(buf_state) samples = buf_state.sampling(n_sample) mask = int(mask, 2) exp += (coef *sum(list(map(lambda x: (-1)**(bin(x & mask).count("1")), samples))) /n_sample) return exp
def adaptive_sample_observable(state, obs, n_sample): """ Args: state (qulacs.QuantumState): obs (qulacs.Observable) n_sample (int): number of samples for each observable Return: :float: sampled expectation value of the observable """ n_term = obs.get_term_count() n_qubits = obs.get_qubit_count() exp = 0 buf_state = QuantumState(n_qubits) ### check the coefficients for each term... coef_list = np.array([abs(obs.get_term(i).get_coef()) for i in range(n_term)]) sum_coef = np.sum(coef_list) ### sort sorted_indices = np.argsort(-coef_list) coef_list.sort() #sorted_coef_list = [coef_list[i] for i in sorted_indices] ### determine sampling wight n_sample_total = n_sample*n_term n_sample_list = n_sample_total*coef_list//sum_coef n_count = np.sum(n_sample_list) n_rest = n_sample_total - n_count n_sample_list[sorted_indices[:n_rest]] += 1 j = 0 for i in range(n_term): if n_sample_list[i] == 0: continue j += n_sample_list[i] pauli_term = obs.get_term(i) coef = pauli_term.get_coef() pauli_id = pauli_term.get_pauli_id_list() pauli_index = pauli_term.get_index_list() if len(pauli_id) == 0: # means identity exp += coef continue buf_state.load(state) measurement_circuit = QuantumCircuit(n_qubits) mask = "".join(["1" if n_qubits - 1 - k in pauli_index else "0" for k in range(n_qubits)]) for single_pauli, index in zip(pauli_id, pauli_index): if single_pauli == 1: measurement_circuit.add_H_gate(index) elif single_pauli == 2: measurement_circuit.add_Sdag_gate(index) measurement_circuit.add_H_gate(index) measurement_circuit.update_quantum_state(buf_state) samples = buf_state.sampling(n_sample_list[i]) mask = int(mask, 2) exp += (coef *sum(list(map(lambda x: (-1)**(bin(x & mask).count("1")), samples))) /n_sample_list[i]) return exp
def cost_phf_sample(Quket, print_level, qulacs_hamiltonian, qulacs_hamiltonianZ, qulacs_s2Z, qulacs_ancZ, coef0_H, coef0_S2, ref, theta_list, samplelist): """Function: Sample Hamiltonian and S**2 expectation values with PHF and PUCCSD. Write out the statistics in csv files. Author(s): Takashi Tsuchimochi """ t1 = time.time() noa = Quket.noa nob = Quket.nob nva = Quket.nva nvb = Quket.nvb n_electrons = Quket.n_electrons n_qubit_system = n_qubits n_qubits = Quket.n_qubits + 1 anc = n_qubit_system ndim1 = Quket.ndim1 state = QuantumState(n_qubits) circuit_rhf = set_circuit_rhfZ(n_qubits, n_electrons) circuit_rhf.update_quantum_state(state) if ref == "phf": circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, theta_list) circuit_uhf.update_quantum_state(state) print("pHF") elif ref == "puccsd": circuit = set_circuit_uccsd(n_qubits, noa, nob, nva, nvb, theta_list, ndim1) for i in range(rho): circuit.update_quantum_state(state) print("UCCSD") if print_level > -1: print("State before projection") utils.print_state(state, n_qubit_system) #### Set post-measurement states #### #poststate0 = state.copy() #poststate1 = state.copy() #circuit0 = QuantumCircuit(n_qubits) #circuit1 = QuantumCircuit(n_qubits) #### Projection to anc = 0 or anc = 1 ### #circuit0.add_gate(P0(0)) #circuit1.add_gate(P1(0)) #circuit0.update_quantum_state(poststate0) #circuit1.update_quantum_state(poststate1) #### Renormalize each state ### #norm0 = poststate0.get_squared_norm() #norm1 = poststate1.get_squared_norm() #poststate0.normalize(norm0) #poststate1.normalize(norm1) ### grid loop ### Ng = 4 beta = [-0.861136311594053, -0.339981043584856, 0.339981043584856, 0.861136311594053] wg = [0.173927422568724, 0.326072577431273, 0.326072577431273, 0.173927422568724] Ng = 2 beta = [0.577350269189626, -0.577350269189626] wg = [0.5, 0.5] ### a list to compute the probability to observe 0 in ancilla qubit p0_list = np.full(n_qubits, 2) p0_list[-1] = 0 ### Array for <HUg>, <S2Ug>, <Ug> # samplelist = [10,100,1000,10000,100000,1000000,10000000] ncyc = 4 prints("", filepath="./log2.txt") for i_sample in samplelist: i_sample_x = i_sample if i_sample == 10000000: print("OK") ncyc = ncyc*10 i_sample_x = 1000000 sampleHUg1 = [] sampleHUg2 = [] sampleHUg3 = [] sampleHUg4 = [] sampleS2Ug1 = [] sampleS2Ug2 = [] sampleS2Ug3 = [] sampleS2Ug4 = [] sampleUg1 = [] sampleUg2 = [] sampleUg3 = [] sampleUg4 = [] # sampleEn = [] # sampleS2 = [] sampleHUg = np.zeros((ncyc, Ng)) sampleS2Ug = np.zeros((ncyc, Ng)) sampleUg = np.zeros((ncyc, Ng)) sampleEn = np.zeros((ncyc, 1)) sampleS2 = np.zeros((ncyc, 1)) for icyc in range(ncyc): prints(f"n_sample = {i_sample_x} ({icyc} / {ncyc})", filepath="./log2.txt") HUg = [] S2Ug = [] Ug = [] Ephf = S2 = Norm = 0 for i in range(Ng): ### Copy quantum state of UHF (cannot be done in real device) ### state_g = QuantumState(n_qubits) state_g.load(state) ### Construct Ug test circuit_ug = QuantumCircuit(n_qubits) ### Hadamard on anc circuit_ug.add_H_gate(anc) controlled_Ug(circuit_ug, n_qubits, anc, np.arccos(beta[i])) circuit_ug.add_H_gate(anc) circuit_ug.update_quantum_state(state_g) ### Set post-measurement states #### poststate0 = state_g.copy() poststate1 = state_g.copy() circuit0 = QuantumCircuit(n_qubits) circuit1 = QuantumCircuit(n_qubits) ### Projection to anc = 0 or anc = 1 ### circuit0.add_gate(P0(anc)) circuit1.add_gate(P1(anc)) circuit0.update_quantum_state(poststate0) circuit1.update_quantum_state(poststate1) ### Renormalize each state ### norm0 = poststate0.get_squared_norm() norm1 = poststate1.get_squared_norm() poststate0.normalize(norm0) poststate1.normalize(norm1) ### Set ancilla qubit of poststate1 to zero (so that it won't be used) ### circuit_anc = QuantumCircuit(n_qubits) circuit_anc.add_X_gate(anc) circuit_anc.update_quantum_state(poststate1) print( test_transition_observable( state_g, qulacs_hamiltonianZ, poststate0, poststate1, 100000)) # exit() ### Probabilities for getting 0 and 1 in ancilla qubit ### p0 = state_g.get_marginal_probability(p0_list) p1 = 1 - p0 ### Compute expectation value <HUg> ### HUg.append(sample_observable(state_g, qulacs_hamiltonianZ, i_sample_x).real) #HUg.append(adaptive_sample_observable(state_g, # qulacs_hamiltonianZ, # i_sample_x).real) ### <S2Ug> ### S2Ug.append(sample_observable(state_g, qulacs_s2Z, i_sample_x).real) #S2Ug.append(adaptive_sample_observable(state_g, # qulacs_s2Z, # i_sample_x).real) #S2Ug.append(qulacs_s2Z.get_expectation_value(state_g)) #HUg.append(0) #S2Ug.append(0) #Ug.append(p0 - p1) n_term = qulacs_hamiltonianZ.get_term_count() n_sample_total = i_sample_x * n_term # in the worst-case scenario, # Ug is measured as many times as n_sample_total #(required to evaluate HUg) Ug.append(sample_observable(state_g, qulacs_ancZ, i_sample_x*n_term).real) #p0_sample = 0 #for j_sample in range(n_sample_total): # if(p0 > np.random.rand()): # p0_sample += 1 #Ug.append(2*p0_sample/n_sample_total - 1) ### Norm accumulation ### Norm += wg[i]*Ug[i] sampleHUg[icyc, i] = HUg[i] sampleS2Ug[icyc, i] = S2Ug[i] sampleUg[icyc, i] = Ug[i] #print('p0 : ',p0,' p1 : ',p1, ' p0 - p1 : ',p0-p1) sampleHUg1.append(HUg[0]) sampleHUg2.append(HUg[1]) #sampleHUg3.append(HUg[2]) #sampleHUg4.append(HUg[3]) sampleS2Ug1.append(S2Ug[0]) sampleS2Ug2.append(S2Ug[1]) #sampleS2Ug3.append(S2Ug[2]) #sampleS2Ug4.append(S2Ug[3]) sampleUg1.append(Ug[0]) sampleUg2.append(Ug[1]) #sampleUg3.append(Ug[2]) #sampleUg4.append(Ug[3]) ### Energy calculation <HP>/<P> and <S**2P>/<P> ### Ephf = 0 for i in range(Ng): Ephf += wg[i]*HUg[i]/Norm S2 += wg[i]*S2Ug[i]/Norm # print(" <S**2> = ", S2, '\n') Ephf += coef0_H S2 += coef0_S2 sampleEn[icyc, 0] = Ephf sampleS2[icyc, 0] = S2 # print(" <E[PHF]> (Nsample = ",i_sample,") = ", Ephf) #print(f"(n_sample = {i_sample}): sample HUg1\n",sampleHUg1) #print(f"(n_sample = {i_sample}): sample HUg2\n",sampleHUg2) #print(f"(n_sample = {i_sample}): sample HUg3\n",sampleHUg3) #print(f"(n_sample = {i_sample}): sample HUg4\n",sampleHUg4) #print(f"(n_sample = {i_sample}): sample S2Ug1\n",sampleS2Ug1) #print(f"(n_sample = {i_sample}): sample S2Ug2\n",sampleS2Ug2) #print(f"(n_sample = {i_sample}): sample S2Ug3\n",sampleS2Ug3) #print(f"(n_sample = {i_sample}): sample S2Ug4\n",sampleS2Ug4) #print(f"(n_sample = {i_sample}): sample Ug1\n",sampleUg1) #print(f"(n_sample = {i_sample}): sample Ug2\n",sampleUg2) #print(f"(n_sample = {i_sample}): sample Ug3\n",sampleUg3) #print(f"(n_sample = {i_sample}): sample Ug4\n",sampleUg4) #print(f"(n_sample = {i_sample}): sample HUg1\n",sampleHUg1) #print(f"(n_sample = {i_sample}): sample HUg2\n",sampleHUg2) #print(f"(n_sample = {i_sample}): sample HUg3\n",sampleHUg3) #print(f"(n_sample = {i_sample}): sample HUg4\n",sampleHUg4) #print(f"(n_sample = {i_sample}): sample En\n",sampleEn) #print(f"(n_sample = {i_sample}): sample S2\n",sampleS2) with open(f"./Ug_{i_sample}.csv", "w") as fUg: writer = csv.writer(fUg) writer.writerows(sampleUg) with open(f"./HUg_{i_sample}.csv", "w") as fHUg: writer = csv.writer(fHUg) writer.writerows(sampleHUg) with open(f"./S2Ug_{i_sample}.csv", "w") as fS2Ug: writer = csv.writer(fS2Ug) writer.writerows(sampleS2Ug) with open(f"./En_{i_sample}.csv", "w") as fEn: writer = csv.writer(fEn) writer.writerows(sampleEn) with open(f"./S2_{i_smaple}.csv", "w") as fS2: writer = csv.writer(fS2) writer.writerows(sampleS2) return Ephf, S2
def test_transition_observable(state, obs, poststate0, poststate1, n_sample): """ Args: state (qulacs.QuantumState): This includes entangled ancilla (n_qubits = n_qubit_system + 1) obs (qulacs.Observable): This does not include ancilla Z (n_qubit_system) poststate0 (qulacs.QuantumState): post-measurement state when ancilla = 0 (n_qubit_system) poststate1 (qulacs.QuantumState): post-measurement state when ancilla = 1 (n_qubit_system) n_sample (int): number of samples for each observable Return: :float: sampled expectation value of the observable """ n_term = obs.get_term_count() n_qubits = obs.get_qubit_count() p0 = state.get_zero_probability(n_qubits - 1) p1 = 1 - p0 opt = f"0{n_qubits}b" prints(f"p0: {p0} p1: {p1}") print_state(poststate0, name="post(0)") prints("post(1)") print_state(poststate1, name="post(1)") expH = 0 exp = [] coef = [] buf_state = QuantumState(n_qubits) for i in range(n_term): pauli_term = obs.get_term(i) coef.append(pauli_term.get_coef().real) pauli_id = pauli_term.get_pauli_id_list() pauli_index = pauli_term.get_index_list() if len(pauli_id) == 0: # means identity exp.extend(coef) continue buf_state.load(state) measurement_circuit = QuantumCircuit(n_qubits) mask = "".join(["1" if n_qubits - 1 - k in pauli_index else "0" for k in range(n_qubits)]) measure_observable = QubitOperator((), 1) #measure_observable = QubitOperator('Z%d' % n_qubits) for single_pauli, index in zip(pauli_id, pauli_index): if single_pauli == 1: ### X measurement_circuit.add_H_gate(index) measure_observable *= QubitOperator(f"X{index}") elif single_pauli == 2: ### Y measurement_circuit.add_Sdag_gate(index) measurement_circuit.add_H_gate(index) measure_observable *= QubitOperator(f"Y{index}") elif single_pauli == 3: ### Z measure_observable *= QubitOperator(f"Z{index}") qulacs_measure_observable \ = create_observable_from_openfermion_text( str(measure_observable)) ### p0 ### H0 = qulacs_measure_observable.get_expectation_value(poststate0) ### p1 ### H1 = qulacs_measure_observable.get_expectation_value(poststate1) prob = p0*H0 - p1*H1 # print(prob, qulacs_measure_observable.get_expectation_value(state), obs.get_expectation_value(state)) prob = qulacs_measure_observable.get_expectation_value(state) expH += coef[i]*prob # measurement_circuit.update_quantum_state(buf_state) # samples = buf_state.sampling(n_sample) # print('samples? ',format(samples[0],opt)) # print("I = :",'%5d' % i, " h_I ", '%10.5f' % coef[i], " <P_I> ", '%10.5f' % exp[i]) # mask = int(mask, 2) # print(sum(list(map(lambda x: (-1) **(bin(x & mask).count('1')), samples)))) # print(coef*sum(list(map(lambda x: (-1) ** # (bin(x & mask).count('1')), samples)))) # expH += coef[i] * exp[i] # samples = buf_state.sampling(n_sample) # mask = int(mask, 2) # prob = sum(list(map(lambda x: (-1) ** # (bin(x & mask).count('1')), samples)))/n_sample # measure_list = list(map(int,np.ones(n_qubits)*2)) # for j in pauli_index: # measure_list[j] = 1 # print(qulacs_measure_observable.get_expectation_value(state)) # expH += coef[i] * prob print(f"coef: {coef[i]:10.5f} prob: {prob:10.5f}") return expH
def test_observable(state, obs, obsZ, n_sample): """Function Args: state (qulacs.QuantumState): This includes entangled ancilla (n_qubits = n_qubit_system + 1) obs (qulacs.Observable): This does not include ancilla Z (n_qubit_system) obsZ (qulacs.Observable): Single Pauli Z for ancilla (1) poststate0 (qulacs.QuantumState): post-measurement state when ancilla = 0 (n_qubit_system) poststate1 (qulacs.QuantumState): post-measurement state when ancilla = 1 (n_qubit_system) n_sample (int): number of samples for each observable Return: :float: sampled expectation value of the observable Author(s): Takashi Tsuchimochi """ n_term = obs.get_term_count() n_qubits = obs.get_qubit_count() p0 = state.get_zero_probability(n_qubits) p1 = 1 - p0 opt = f"0{n_qubits}b" expH = 0 exp = [] coef = [] buf_state = QuantumState(n_qubits) for i in range(n_term): pauli_term = obs.get_term(i) coef.append(pauli_term.get_coef().real) pauli_id = pauli_term.get_pauli_id_list() pauli_index = pauli_term.get_index_list() if len(pauli_id) == 0: # means identity exp.extend(coef) continue buf_state.load(state) measurement_circuit = QuantumCircuit(n_qubits) mask = "".join(["1" if n_qubits - 1 - k in pauli_index else "0" for k in range(n_qubits)]) measure_observable = QubitOperator((), 1) for single_pauli, index in zip(pauli_id, pauli_index): if single_pauli == 1: ### X measurement_circuit.add_H_gate(index) measure_observable *= QubitOperator(f"X{index}") elif single_pauli == 2: ### Y measurement_circuit.add_Sdag_gate(index) measurement_circuit.add_H_gate(index) measure_observable *= QubitOperator(f"Y{index}") elif single_pauli == 3: ### Z measure_observable *= QubitOperator(f"Z{index}") qulacs_measure_observable \ = create_observable_from_openfermion_text( str(measure_observable)) measurement_circuit.update_quantum_state(buf_state) #exp.append(obsZ.get_expectation_value(buf_state).real) samples = buf_state.sampling(n_sample) #print(f"samples? {format(samples[0], opt)}") #print(f"I = {i:5d} h_I = {coef[i]:10.5f} <P_I> = {exp[i]:10.5f}") #mask = int(mask, 2) #print(sum(list(map(lambda x: (-1)**(bin(x & mask).count('1')), # samples)))) #print(coef*sum(list(map(lambda x: (-1)**(bin(x & mask).count('1')), # samples)))) expH += coef[i]*exp[i] samples = buf_state.sampling(n_sample) mask = int(mask, 2) prob = (sum(list(map(lambda x: (-1)**(bin(x & mask).count("1")), samples))) /n_sample) measure_list = list(map(int, np.ones(n_qubits)*2)) for j in pauli_index: measure_list[j] = 1 #print(qulacs_measure_observable.get_expectation_value(state)) expH += coef[i]*prob #print(f"coef: {coef[i]:10.5f} prob: {prob:10.5f}") return expH
def cost_proj(Quket, print_level, qulacs_hamiltonianZ, qulacs_s2Z, coef0_H, coef0_S2, kappa_list, theta_list=0, threshold=0.01): """Function: Energy functional for projected methods (phf, puccsd, puccd, opt_puccd) Author(s): Takashi Tsuchimochi """ t1 = time.time() noa = Quket.noa nob = Quket.nob nva = Quket.nva nvb = Quket.nvb n_electrons = Quket.n_electrons rho = Quket.rho DS = Quket.DS anc = Quket.anc n_qubit_system = Quket.n_qubits n_qubits = n_qubit_system + 1 # opt_psauccdとかはndimの計算が異なるけどこっちを使う? #ndim1 = noa * nva + nob * nvb #ndim2aa = int(noa * (noa - 1) * nva * (nva - 1) / 4) #ndim2ab = int(noa * nob * nva * nvb) #ndim2bb = int(nob * (nob - 1) * nvb * (nvb - 1) / 4) #ndim2 = ndim2aa + ndim2ab + ndim2bb ndim1 = Quket.ndim1 ndim2 = Quket.ndim2 ndim = Quket.ndim ref = Quket.ansatz state = QuantumState(n_qubits) if noa == nob: circuit_rhf = set_circuit_rhfZ(n_qubits, n_electrons) else: circuit_rhf = set_circuit_rohfZ(n_qubits, noa, nob) circuit_rhf.update_quantum_state(state) if ref == "phf": circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, kappa_list) circuit_uhf.update_quantum_state(state) elif ref == "sghf": circuit_ghf = set_circuit_ghfZ(n_qubits, noa + nob, nva + nvb, kappa_list) circuit_ghf.update_quantum_state(state) elif ref == "puccsd": # First prepare UHF determinant circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, kappa_list) circuit_uhf.update_quantum_state(state) # Then prepare UCCSD theta_list_rho = theta_list / rho circuit = set_circuit_uccsd(n_qubits, noa, nob, nva, nvb, 0, theta_list_rho, ndim1) for i in range(rho): circuit.update_quantum_state(state) elif ref == "puccd": # First prepare UHF determinant circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, kappa_list) circuit_uhf.update_quantum_state(state) # Then prepare UCCD theta_list_rho = theta_list / rho circuit = set_circuit_uccd(n_qubits, noa, nob, nva, nvb, theta_list_rho) for i in range(rho): circuit.update_quantum_state(state) elif ref == "opt_puccd": if DS: # First prepare UHF determinant circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, theta_list) circuit_uhf.update_quantum_state(state) # Then prepare UCCD theta_list_rho = theta_list[ndim1:] / rho circuit = set_circuit_uccd(n_qubits, noa, nob, nva, nvb, theta_list_rho) for i in range(rho): circuit.update_quantum_state(state) else: # First prepare UCCD theta_list_rho = theta_list[ndim1:] / rho circuit = set_circuit_uccd(n_qubits, noa, nob, nva, nvb, theta_list_rho) for i in range(rho): circuit.update_quantum_state(state) # then rotate circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, theta_list) circuit_uhf.update_quantum_state(state) elif ref == "opt_psauccd": # ここが問題 # ndim2が他と異なる #theta_list_rho = theta_list[ndim1 : ndim1+ndim2]/rho theta_list_rho = theta_list[ndim1:] / rho circuit = set_circuit_sauccd(n_qubits, noa, nva, theta_list_rho) for i in range(rho): circuit.update_quantum_state(state) circuit_uhf = set_circuit_uhfZ(n_qubits, noa, nob, nva, nvb, theta_list) circuit_uhf.update_quantum_state(state) if print_level > 0: if ref in ("uhf", "phf", "suhf", "sghf"): SaveTheta(ndim, kappa_list, cf.tmp) else: SaveTheta(ndim, theta_list, cf.tmp) if print_level > 1: prints("State before projection") print_state(state, n_qubits=n_qubit_system) if ref in ("puccsd", "opt_puccd"): print_amplitudes(theta_list, noa, nob, nva, nvb, threshold) ### grid loop ### ### a list to compute the probability to observe 0 in ancilla qubit ### Array for <HUg>, <S2Ug>, <Ug> Ep = S2 = Norm = 0 nalpha = max(Quket.projection.euler_ngrids[0], 1) nbeta = max(Quket.projection.euler_ngrids[1], 1) ngamma = max(Quket.projection.euler_ngrids[2], 1) HUg = np.empty(nalpha * nbeta * ngamma) S2Ug = np.empty(nalpha * nbeta * ngamma) Ug = np.empty(nalpha * nbeta * ngamma) ig = 0 for ialpha in range(nalpha): alpha = Quket.projection.sp_angle[0][ialpha] alpha_coef = Quket.projection.sp_weight[0][ialpha] for ibeta in range(nbeta): beta = Quket.projection.sp_angle[1][ibeta] beta_coef = (Quket.projection.sp_weight[1][ibeta] * Quket.projection.dmm[ibeta]) for igamma in range(ngamma): gamma = Quket.projection.sp_angle[2][igamma] gamma_coef = Quket.projection.sp_weight[2][igamma] ### Copy quantum state of UHF (cannot be done in real device) ### state_g = QuantumState(n_qubits) state_g.load(state) ### Construct Ug test circuit_ug = QuantumCircuit(n_qubits) ### Hadamard on anc circuit_ug.add_H_gate(anc) #circuit_ug.add_X_gate(anc) #controlled_Ug(circuit_ug, n_qubits, anc, beta) controlled_Ug_gen(circuit_ug, n_qubits, anc, alpha, beta, gamma) #circuit_ug.add_X_gate(anc) circuit_ug.add_H_gate(anc) circuit_ug.update_quantum_state(state_g) ### Compute expectation value <HUg> ### HUg[ig] = qulacs_hamiltonianZ.get_expectation_value(state_g) ### <S2Ug> ### # print_state(state_g) S2Ug[ig] = qulacs_s2Z.get_expectation_value(state_g) ### <Ug> ### p0 = state_g.get_zero_probability(anc) p1 = 1 - p0 Ug[ig] = p0 - p1 ### Norm accumulation ### Norm += alpha_coef * beta_coef * gamma_coef * Ug[ig] Ep += alpha_coef * beta_coef * gamma_coef * HUg[ig] S2 += alpha_coef * beta_coef * gamma_coef * S2Ug[ig] ig += 1 # print('p0 : ',p0,' p1 : ',p1, ' p0 - p1 : ',p0-p1) # print("Time: ",t2-t1) ### Energy calculation <HP>/<P> and <S**2P>/<P> ### Ep /= Norm S2 /= Norm Ep += coef0_H S2 += coef0_S2 t2 = time.time() cpu1 = t2 - t1 if print_level == -1: prints(f"Initial E[{ref}] = {Ep:.12f} <S**2> = {S2:17.15f} " f"rho = {rho}") elif print_level == 1: cput = t2 - cf.t_old cf.t_old = t2 cf.icyc += 1 prints(f"{cf.icyc:5d}: E[{ref}] = {Ep:.12f} <S**2> = {S2:17.15f} " f"CPU Time = {cput:5.2f} ({cpu1:2.2f} / step)") elif print_level > 1: prints(f"Final: E[{ref}] = {Ep:.12f} <S**2> = {S2:17.15f} " f"rho = {rho}") print_state(state, n_qubits=n_qubits - 1) if ref in ("puccsd", "opt_puccd"): print_amplitudes(theta_list, noa, nob, nva, nvb) prints("HUg", HUg) prints("Ug", Ug) # Store wave function Quket.state = state return Ep, S2
class QulacsDevice(QubitDevice): """Qulacs device""" name = "Qulacs device" short_name = "qulacs.simulator" pennylane_requires = ">=0.11.0" version = __version__ author = "Steven Oud and Xanadu" gpu_supported = GPU_SUPPORTED _capabilities = { "model": "qubit", "tensor_observables": True, "inverse_operations": True } _operation_map = { "QubitStateVector": None, "BasisState": None, "QubitUnitary": None, "Toffoli": gate.TOFFOLI, "CSWAP": gate.FREDKIN, "CRZ": crz, "SWAP": gate.SWAP, "CNOT": gate.CNOT, "CZ": gate.CZ, "S": gate.S, "T": gate.T, "RX": gate.RX, "RY": gate.RY, "RZ": gate.RZ, "PauliX": gate.X, "PauliY": gate.Y, "PauliZ": gate.Z, "Hadamard": gate.H, "PhaseShift": phase_shift, } _observable_map = { "PauliX": "X", "PauliY": "Y", "PauliZ": "Z", "Identity": "I", "Hadamard": None, "Hermitian": None, } operations = _operation_map.keys() observables = _observable_map.keys() # Add inverse gates to _operation_map _operation_map.update({k + ".inv": v for k, v in _operation_map.items()}) def __init__(self, wires, shots=1000, analytic=True, gpu=False, **kwargs): super().__init__(wires=wires, shots=shots, analytic=analytic) if gpu: if not QulacsDevice.gpu_supported: raise DeviceError( "GPU not supported with installed version of qulacs. " "Please install 'qulacs-gpu' to use GPU simulation.") self._state = QuantumStateGpu(self.num_wires) else: self._state = QuantumState(self.num_wires) self._circuit = QuantumCircuit(self.num_wires) self._pre_rotated_state = self._state.copy() def apply(self, operations, **kwargs): rotations = kwargs.get("rotations", []) self.apply_operations(operations) self._pre_rotated_state = self._state.copy() # Rotating the state for measurement in the computational basis if rotations: self.apply_operations(rotations) def apply_operations(self, operations): """Apply the circuit operations to the state. This method serves as an auxiliary method to :meth:`~.QulacsDevice.apply`. Args: operations (List[pennylane.Operation]): operations to be applied """ for i, op in enumerate(operations): if i > 0 and isinstance(op, (QubitStateVector, BasisState)): raise DeviceError( "Operation {} cannot be used after other Operations have already been applied " "on a {} device.".format(op.name, self.short_name)) if isinstance(op, QubitStateVector): self._apply_qubit_state_vector(op) elif isinstance(op, BasisState): self._apply_basis_state(op) elif isinstance(op, QubitUnitary): self._apply_qubit_unitary(op) elif isinstance(op, (CRZ, PhaseShift)): self._apply_matrix(op) else: self._apply_gate(op) def _apply_qubit_state_vector(self, op): """Initialize state with a state vector""" wires = op.wires input_state = op.parameters[0] if len(input_state) != 2**len(wires): raise ValueError("State vector must be of length 2**wires.") if input_state.ndim != 1 or len(input_state) != 2**len(wires): raise ValueError("State vector must be of length 2**wires.") if not np.isclose(np.linalg.norm(input_state, 2), 1.0, atol=tolerance): raise ValueError("Sum of amplitudes-squared does not equal one.") input_state = _reverse_state(input_state) # call qulacs' state initialization self._state.load(input_state) def _apply_basis_state(self, op): """Initialize a basis state""" wires = op.wires par = op.parameters # translate from PennyLane to Qulacs wire order bits = par[0][::-1] n_basis_state = len(bits) if not set(bits).issubset({0, 1}): raise ValueError( "BasisState parameter must consist of 0 or 1 integers.") if n_basis_state != len(wires): raise ValueError( "BasisState parameter and wires must be of equal length.") basis_state = 0 for bit in bits: basis_state = (basis_state << 1) | bit # call qulacs' basis state initialization self._state.set_computational_basis(basis_state) def _apply_qubit_unitary(self, op): """Apply unitary to state""" # translate op wire labels to consecutive wire labels used by the device device_wires = self.map_wires(op.wires) par = op.parameters if len(par[0]) != 2**len(device_wires): raise ValueError( "Unitary matrix must be of shape (2**wires, 2**wires).") if op.inverse: par[0] = par[0].conj().T # reverse wires (could also change par[0]) reverse_wire_labels = device_wires.tolist()[::-1] unitary_gate = gate.DenseMatrix(reverse_wire_labels, par[0]) self._circuit.add_gate(unitary_gate) unitary_gate.update_quantum_state(self._state) def _apply_matrix(self, op): """Apply predefined gate-matrix to state (must follow qulacs convention)""" # translate op wire labels to consecutive wire labels used by the device device_wires = self.map_wires(op.wires) par = op.parameters mapped_operation = self._operation_map[op.name] if op.inverse: mapped_operation = self._get_inverse_operation( mapped_operation, device_wires, par) if callable(mapped_operation): gate_matrix = mapped_operation(*par) else: gate_matrix = mapped_operation # gate_matrix is already in correct order => no wire-reversal needed dense_gate = gate.DenseMatrix(device_wires.labels, gate_matrix) self._circuit.add_gate(dense_gate) gate.DenseMatrix(device_wires.labels, gate_matrix).update_quantum_state(self._state) def _apply_gate(self, op): """Apply native qulacs gate""" # translate op wire labels to consecutive wire labels used by the device device_wires = self.map_wires(op.wires) par = op.parameters mapped_operation = self._operation_map[op.name] if op.inverse: mapped_operation = self._get_inverse_operation( mapped_operation, device_wires, par) # Negating the parameters such that it adheres to qulacs par = np.negative(par) # mapped_operation is already in correct order => no wire-reversal needed self._circuit.add_gate(mapped_operation(*device_wires.labels, *par)) mapped_operation(*device_wires.labels, *par).update_quantum_state(self._state) @staticmethod def _get_inverse_operation(mapped_operation, device_wires, par): """Return the inverse of an operation""" if mapped_operation is None: return mapped_operation # if an inverse variant of the operation exists try: inverse_operation = getattr(gate, mapped_operation.get_name() + "dag") except AttributeError: # if the operation is hard-coded try: if callable(mapped_operation): inverse_operation = np.conj(mapped_operation(*par)).T else: inverse_operation = np.conj(mapped_operation).T # if mapped_operation is a qulacs.gate and np.conj is applied on it except TypeError: # else, redefine the operation as the inverse matrix def inverse_operation(*p): # embed the gate in a unitary matrix with shape (2**wires, 2**wires) g = mapped_operation(*p).get_matrix() mat = reduce(np.kron, [np.eye(2)] * len(device_wires)).astype(complex) mat[-len(g):, -len(g):] = g # mat follows PL convention => reverse wire-order reverse_wire_labels = device_wires.tolist()[::-1] gate_mat = gate.DenseMatrix(reverse_wire_labels, np.conj(mat).T) return gate_mat return inverse_operation def analytic_probability(self, wires=None): """Return the (marginal) analytic probability of each computational basis state.""" if self._state is None: return None all_probs = self._abs(self.state)**2 prob = self.marginal_prob(all_probs, wires) return prob def expval(self, observable): if self.analytic: qulacs_observable = Observable(self.num_wires) if isinstance(observable.name, list): observables = [ self._observable_map[obs] for obs in observable.name ] else: observables = [self._observable_map[observable.name]] if None not in observables: applied_wires = self.map_wires(observable.wires).tolist() opp = " ".join([ f"{obs} {applied_wires[i]}" for i, obs in enumerate(observables) ]) qulacs_observable.add_operator(1.0, opp) return qulacs_observable.get_expectation_value( self._pre_rotated_state) # exact expectation value eigvals = self._asarray(observable.eigvals, dtype=self.R_DTYPE) prob = self.probability(wires=observable.wires) return self._dot(eigvals, prob) # estimate the ev return np.mean(self.sample(observable)) @property def state(self): # returns the state after all operations are applied return _reverse_state(self._state.get_vector()) def reset(self): self._state.set_zero_state() self._pre_rotated_state = self._state.copy() self._circuit = QuantumCircuit(self.num_wires)
class QulacsDevice(Device): """Qulacs device""" name = 'Qulacs device' short_name = 'qulacs.simulator' pennylane_requires = '>=0.5.0' version = __version__ author = 'Steven Oud' _capabilities = {'model': 'qubit', 'tensor_observables': True} _operations_map = { 'QubitStateVector': None, 'BasisState': None, 'QubitUnitary': None, 'Toffoli': toffoli, 'CSWAP': CSWAP, 'CRZ': crz, 'Rot': None, 'SWAP': gate.SWAP, 'CNOT': gate.CNOT, 'CZ': gate.CZ, 'S': gate.S, 'Sdg': gate.Sdag, 'T': gate.T, 'Tdg': gate.Tdag, 'RX': gate.RX, 'RY': gate.RY, 'RZ': gate.RZ, 'PauliX': gate.X, 'PauliY': gate.Y, 'PauliZ': gate.Z, 'Hadamard': gate.H } _observable_map = { 'PauliX': X, 'PauliY': Y, 'PauliZ': Z, 'Hadamard': H, 'Identity': I, 'Hermitian': hermitian } operations = _operations_map.keys() observables = _observable_map.keys() def __init__(self, wires, gpu=False, **kwargs): super().__init__(wires=wires) if gpu: if not GPU_SUPPORTED: raise DeviceError( 'GPU not supported with installed version of qulacs. ' 'Please install "qulacs-gpu" to use GPU simulation.') self._state = QuantumStateGpu(wires) else: self._state = QuantumState(wires) self._circuit = QuantumCircuit(wires) self._first_operation = True def apply(self, operation, wires, par): par = np.negative(par) if operation == 'BasisState' and not self._first_operation: raise DeviceError( 'Operation {} cannot be used after other Operations have already been applied ' 'on a {} device.'.format(operation, self.short_name)) self._first_operation = False if operation == 'QubitStateVector': if len(par[0]) != 2**len(wires): raise ValueError('State vector must be of length 2**wires.') self._state.load(par[0]) elif operation == 'BasisState': if len(par[0]) != len(wires): raise ValueError('Basis state must prepare all qubits.') basis_state = 0 for bit in reversed(par[0]): basis_state = (basis_state << 1) | bit self._state.set_computational_basis(basis_state) elif operation == 'QubitUnitary': if len(par[0]) != 2**len(wires): raise ValueError( 'Unitary matrix must be of shape (2**wires, 2**wires).') unitary_gate = gate.DenseMatrix(wires, par[0]) self._circuit.add_gate(unitary_gate) elif operation == 'Rot': self._circuit.add_gate( gate.merge([ gate.RZ(wires[0], par[0]), gate.RY(wires[0], par[1]), gate.RZ(wires[0], par[2]) ])) elif operation in ('CRZ', 'Toffoli', 'CSWAP'): mapped_operation = self._operations_map[operation] if callable(mapped_operation): gate_matrix = mapped_operation(*par) else: gate_matrix = mapped_operation dense_gate = gate.DenseMatrix(wires, gate_matrix) self._circuit.add_gate(dense_gate) else: mapped_operation = self._operations_map[operation] self._circuit.add_gate(mapped_operation(*wires, *par)) @property def state(self): return self._state.get_vector() def pre_measure(self): self._circuit.update_quantum_state(self._state) def expval(self, observable, wires, par): bra = self._state.copy() if isinstance(observable, list): A = self._get_tensor_operator_matrix(observable, par) wires = [item for sublist in wires for item in sublist] else: A = self._get_operator_matrix(observable, par) dense_gate = gate.DenseMatrix(wires, A) dense_gate.update_quantum_state(self._state) expectation = inner_product(bra, self._state) return expectation.real def probabilities(self): states = itertools.product(range(2), repeat=self.num_wires) probs = np.abs(self.state)**2 return OrderedDict(zip(states, probs)) def reset(self): self._state.set_zero_state() self._circuit = QuantumCircuit(self.num_wires) def _get_operator_matrix(self, operation, par): A = self._observable_map[operation] if not callable(A): return A return A(*par) def _get_tensor_operator_matrix(self, obs, par): ops = [self._get_operator_matrix(o, p) for o, p in zip(obs, par)] return functools.reduce(np.kron, ops)
def __run_all(qcirc=None, shots=1, cid=None, backend=None, proc='CPU', out_state=False): if qcirc is None: raise ValueError("quantum circuit must be specified.") qubit_num = qcirc.qubit_num cmem_num = qcirc.cmem_num if cid is None: cid = list(range(cmem_num)) if cmem_num < len(cid): raise ValueError( "length of cid must be less than classical resister size of qcirc") # # initialize # if proc == 'CPU': qstate = QuantumState(qubit_num) else: from qulacs import QuantumStateGpu qstate = QuantumStateGpu(qubit_num) cmem = [0] * cmem_num # # before measurement gate # while True: kind = qcirc.kind_first() if kind is None or kind is cfg.MEASURE or kind is cfg.RESET: break (kind, qid, para, c, ctrl) = qcirc.pop_gate() if ctrl is None or (ctrl is not None and cmem[ctrl] == 1): __qulacs_operate_qgate(qstate, qubit_num, kind=kind, qid=qid, phase=para[0], phase1=para[1], phase2=para[2]) if kind is None: result = Result() result.qubit_num = qubit_num result.cmem_num = cmem_num result.cid = cid result.shots = shots result.frequency = None result.backend = backend if out_state is True: result.qstate = __transform_qlazy_qstate(qstate) result.cmem = __transform_qlazy_cmem(cmem) return result # # after measurement gate # if set(qcirc.kind_list()) == {cfg.MEASURE}: q_list = [] while True: kind = qcirc.kind_first() if kind is None: break (kind, qid, para, c, ctrl) = qcirc.pop_gate() q_list.append(qid[0]) frequency, qstate = __qulacs_measure_shots(qstate, q_list, shots) result = Result() result.qubit_num = qubit_num result.cmem_num = cmem_num result.cid = cid result.shots = shots result.frequency = frequency result.backend = backend if out_state is True: result.qstate = __transform_qlazy_qstate(qstate) result.cmem = __transform_qlazy_cmem(cmem) return result frequency = Counter() qstate_tmp = None for _ in range(shots): qstate_tmp = qstate.copy() qcirc_tmp = qcirc.clone() while True: kind = qcirc_tmp.kind_first() if kind is None: break if kind == cfg.MEASURE: (kind, qid, para, c, ctrl) = qcirc_tmp.pop_gate() mval = __qulacs_measure(qstate_tmp, qubit_num, qid[0]) if c is not None: cmem[c] = mval elif kind == cfg.RESET: (kind, qid, para, c, ctrl) = qcirc_tmp.pop_gate() __qulacs_reset(qstate_tmp, qubit_num, qid[0]) else: (kind, qid, para, c, ctrl) = qcirc_tmp.pop_gate() if (ctrl is None or (ctrl is not None and cmem[ctrl] == 1)): __qulacs_operate_qgate(qstate_tmp, qubit_num, kind=kind, qid=qid, phase=para[0], phase1=para[1], phase2=para[2]) if len(cmem) > 0: mval = ''.join(map(str, [cmem[i] for i in cid])) frequency[mval] += 1 if qstate_tmp is not None: qstate.load(qstate_tmp.get_vector()) if len(frequency) == 0: frequency = None result = Result() result.qubit_num = qubit_num result.cmem_num = cmem_num result.cid = cid result.shots = shots result.frequency = frequency result.backend = backend if out_state is True: result.qstate = __transform_qlazy_qstate(qstate) result.cmem = __transform_qlazy_cmem(cmem) return result