def test_reorder_fermionic_modes(): ref_op = get_interaction_operator( FermionOperator( """ 0.0 [] + 1.0 [0^ 0] + 1.0 [1^ 1] + 1.0 [0^ 1^ 2 3] + 1.0 [1^ 1^ 2 2] """ ) ) reordered_op = get_interaction_operator( FermionOperator( """ 0.0 [] + 1.0 [0^ 0] + 1.0 [2^ 2] + 1.0 [0^ 2^ 1 3] + 1.0 [2^ 2^ 1 1] """ ) ) spin_block_op = reorder_fermionic_modes(ref_op, [0, 2, 1, 3]) assert reordered_op == spin_block_op spin_block_qubit_op = jordan_wigner(spin_block_op) interleaved_qubit_op = jordan_wigner(ref_op) spin_block_spectrum = eigenspectrum(spin_block_qubit_op) interleaved_spectrum = eigenspectrum(interleaved_qubit_op) assert np.allclose(spin_block_spectrum, interleaved_spectrum)
def __init__(self, orbprop, orb_qubit_map=None, symm_eigval_map=None): ham_fop = construct_exact_ham(orbprop) ham_qop = openfermion.jordan_wigner(ham_fop) n_site = openfermion.count_qubits(ham_qop) if symm_eigval_map is not None: symm_paulistr = symm.symmetry_pauli_string( orbprop, operation_list=list(symm_eigval_map)) for symmop, qop in symm_paulistr.items(): print('[ham_qop, {:5s}] = [ham_qop, {}] = {}'.format( symmop, str(qop), openfermion.commutator(ham_qop, qop))) self.remover = symm.SymmRemover(n_site, list(symm_paulistr.values())) self.remover.set_eigvals( [symm_eigval_map[symm] for symm in symm_paulistr]) ham_qop_tapered = self.remover.remove_symm_qubits(ham_qop) print(self.remover) print('len(ham ) = ', len(ham_qop.terms)) print('len(ham[tapered]) = ', len(ham_qop_tapered.terms)) ham_qop = ham_qop_tapered self.ham_fop = ham_fop self.ham_qop = ham_qop self.ham_tensor = openfermion.get_sparse_operator(ham_qop) self.n_site = n_site self.n_qubit = openfermion.count_qubits(ham_qop) nterm = [0] * ( n_site + 1 ) # number of paulistrs which length is n (n=0,1,..,n_site). for k in ham_qop.terms: nterm[len(k)] += 1 self.nterm = nterm
def test_get_ground_state_rdm_from_qubit_op(self): # Given n_sites = 2 U = 5.0 fhm = fermi_hubbard( x_dimension=n_sites, y_dimension=1, tunneling=1.0, coulomb=U, chemical_potential=U / 2, magnetic_field=0, periodic=False, spinless=False, particle_hole_symmetry=False, ) fhm_qubit = jordan_wigner(fhm) fhm_int = get_interaction_operator(fhm) e, wf = jw_get_ground_state_at_particle_number( get_sparse_operator(fhm), n_sites ) # When rdm = get_ground_state_rdm_from_qubit_op( qubit_operator=fhm_qubit, n_particles=n_sites ) # Then self.assertAlmostEqual(e, rdm.expectation(fhm_int))
def __init__(self, hamiltonian: Union[openfermion.DiagonalCoulombHamiltonian, openfermion.FermionOperator, openfermion.InteractionOperator, openfermion.QubitOperator], use_linear_op: bool = False) -> None: """ Args: hamiltonian: The Hamiltonian. use_linear_op: Whether to use a LinearOperator instead of a sparse matrix to compute expectation values. Using a LinearOperator is more memory-efficient but results in much slower expectation value computation. """ self.hamiltonian = hamiltonian if isinstance(hamiltonian, openfermion.QubitOperator): hamiltonian_qubit_op = hamiltonian else: hamiltonian_qubit_op = openfermion.jordan_wigner(hamiltonian) self.variance_bound = hamiltonian_qubit_op.induced_norm(order=1)**2 if use_linear_op: self._hamiltonian_linear_op = openfermion.LinearQubitOperator( hamiltonian_qubit_op) else: self._hamiltonian_linear_op = openfermion.get_sparse_operator( hamiltonian_qubit_op)
def test_run_psi4(self): geometry = { "sites": [{ 'species': 'H', 'x': 0, 'y': 0, 'z': 0 }, { 'species': 'H', 'x': 0, 'y': 0, 'z': 1.7 }] } results, hamiltonian = run_psi4(geometry, save_hamiltonian=True) self.assertAlmostEqual(results['energy'], -0.8544322638069642) self.assertEqual(results['n_alpha'], 1) self.assertEqual(results['n_beta'], 1) self.assertEqual(results['n_mo'], 2) self.assertEqual(results['n_frozen_core'], 0) self.assertEqual(results['n_frozen_valence'], 0) self.assertEqual(hamiltonian.n_qubits, 4) qubit_operator = qubit_operator_sparse(jordan_wigner(hamiltonian)) energy, state = jw_get_ground_state_at_particle_number( qubit_operator, 2) results_cisd, hamiltonian = run_psi4(geometry, method='ccsd') # For this system, the CCSD energy should be exact. self.assertAlmostEqual(energy, results_cisd['energy'])
def __init__(self, name, geometry, multiplicity, charge, n_orbitals, n_electrons, basis='sto-3g', frozen_els=None): self.name = name self.multiplicity = multiplicity self.charge = charge self.basis = basis self.geometry = geometry self.molecule_data = MolecularData(geometry=self.geometry, basis=basis, multiplicity=self.multiplicity, charge=self.charge) self.molecule_psi4 = run_psi4( self.molecule_data, run_fci=True) # old version of openfermion # Hamiltonian transforms self.molecule_ham = self.molecule_psi4.get_molecular_hamiltonian() self.hf_energy = self.molecule_psi4.hf_energy.item( ) # old version of openfermion self.fci_energy = self.molecule_psi4.fci_energy.item( ) # old version of openfermion # TODO: the code below corresponds to the most recent version in the opefermion documentation. # However it has problems with ray??? # calculate_molecule_psi4 = run_pyscf(self.molecule_data, run_scf=True, run_cisd=True, run_fci=True) # self.molecule_ham = calculate_molecule_psi4.get_molecular_hamiltonian() # self.hf_energy = calculate_molecule_psi4.hf_energy # self.fci_energy = float(calculate_molecule_psi4.fci_energy) # del calculate_molecule_psi4 self.energy_eigenvalues = None # use this only if calculating excited states if frozen_els is None: self.n_electrons = n_electrons self.n_orbitals = n_orbitals self.n_qubits = n_orbitals self.fermion_ham = get_fermion_operator(self.molecule_ham) else: self.n_electrons = n_electrons - len(frozen_els['occupied']) self.n_orbitals = n_orbitals - len(frozen_els['occupied']) - len( frozen_els['unoccupied']) self.n_qubits = self.n_orbitals self.fermion_ham = freeze_orbitals( get_fermion_operator(self.molecule_ham), occupied=frozen_els['occupied'], unoccupied=frozen_els['unoccupied'], prune=True) self.jw_qubit_ham = jordan_wigner(self.fermion_ham) # this is used only for calculating excited states. list of [term_index, term_state] self.H_lower_state_terms = None
def operations(self, qubits: Sequence[cirq.Qid]) -> cirq.OP_TREE: """Returns qubit operators based on STO-3G and UCCSD ansatz""" _symbols = list(self.params()) _ucc_operator = self._fermionic_operators # self._get_fermionic_operators() for i, fo in enumerate(_ucc_operator[::2]): # Jordan-Wigner transform each fermionic operator + its Hermitian conjugate qo_list = list(of.jordan_wigner(fo - of.hermitian_conjugated(fo))) yield IGeneralizedUCCSD.qubit_to_gate_operators( qubit_operators=qo_list, qubits=qubits, par=_symbols[i])
def test_get_diagonal_component_polynomial_tensor(self): fermion_op = FermionOperator("0^ 1^ 2^ 0 1 2", 1.0) fermion_op += FermionOperator("0^ 1^ 2^ 0 1 3", 2.0) fermion_op += FermionOperator((), 3.0) polynomial_tensor = get_polynomial_tensor(fermion_op) diagonal_op, remainder_op = get_diagonal_component(polynomial_tensor) self.assertTrue((diagonal_op + remainder_op) == polynomial_tensor) diagonal_qubit_op = jordan_wigner(get_fermion_operator(diagonal_op)) remainder_qubit_op = jordan_wigner(get_fermion_operator(remainder_op)) for term in diagonal_qubit_op.terms: for pauli in term: self.assertTrue(pauli[1] == "Z") for term in remainder_qubit_op.terms: is_diagonal = True for pauli in term: if pauli[1] != "Z": is_diagonal = False break self.assertFalse(is_diagonal)
def test_get_diagonal_component_interaction_op(self): fermion_op = FermionOperator("1^ 1", 0.5) fermion_op += FermionOperator("2^ 2", 0.5) fermion_op += FermionOperator("1^ 2^ 0 3", 0.5) diagonal_op, remainder_op = get_diagonal_component( get_interaction_operator(fermion_op)) self.assertTrue((diagonal_op + remainder_op) == get_interaction_operator(fermion_op)) diagonal_qubit_op = jordan_wigner(diagonal_op) remainder_qubit_op = jordan_wigner(remainder_op) for term in diagonal_qubit_op.terms: for pauli in term: self.assertTrue(pauli[1] == "Z") is_diagonal = True for term in remainder_qubit_op.terms: for pauli in term: if pauli[1] != "Z": is_diagonal = False break self.assertFalse(is_diagonal)
def __init__(self, fermion_ham, n_orbitals, n_electrons): self.name = '{}_e_{}_orb'.format(n_electrons, n_orbitals) self.n_electrons = n_electrons self.n_orbitals = n_orbitals self.n_qubits = self.n_orbitals self.fermion_ham = fermion_ham self.qubit_ham = jordan_wigner(self.fermion_ham) self.hf_energy = 0 # wild guess self.H_lower_state_terms = None
def get_mb_wavefunction_circuit(packed_amplitudes: ndarray, n_spin_orb, n_electron, n_gadgets): fermion_generator = uccsd_singlet_generator(packed_amplitudes, n_spin_orb, n_electron) qubit_generator = jordan_wigner(fermion_generator) qubit_generator.compress() mb_wavefunction_circuit = generate_hf_wavefunction_circuit(n_spin_orb, n_electron//2, n_electron//2) for pauli, coeff in list(qubit_generator.terms.items())[:n_gadgets]: pauli_evolution(pauli, coeff, mb_wavefunction_circuit) return mb_wavefunction_circuit
def single_test(i): N = 8 #k = np.random.rand(N,N) #k -= (k+k.T)/2 # random real antisymmetric matrix k = get_random_antihermite_mat(N) umat = scipy.linalg.expm(k) #print(umat) c1 = freqerica.circuit.rotorb.OrbitalRotation(umat) from openfermion import FermionOperator, jordan_wigner, get_sparse_operator fop = FermionOperator() for p in range(N): for q in range(N): fop += FermionOperator(((p, 1), (q, 0)), k[p, q]) qop = jordan_wigner(fop) #print(qop) #from freqerica.circuit.trotter import TrotterStep from freqerica.util.qulacsnize import convert_state_vector import qulacs #M = 100 #c2 = TrotterStep(N, qop/M) s1 = qulacs.QuantumState(N) s1.set_Haar_random_state() #s2 = s1.copy() s3 = convert_state_vector(N, s1.get_vector()) c1._circuit.update_quantum_state(s1) #for i in range(M): c2._circuit.update_quantum_state(s2) s3 = scipy.sparse.linalg.expm_multiply(get_sparse_operator(qop), s3) #ip12 = qulacs.state.inner_product(s1, s2) ip13 = np.conjugate(convert_state_vector(N, s1.get_vector())).dot(s3) #ip23 = np.conjugate(convert_state_vector(N, s2.get_vector())).dot(s3) #print('dot(s1,s2)', abs(ip12), ip12) #print('dot(s1,s3)', abs(ip13), ip13) #print('dot(s2,s3)', abs(ip23), ip23) print('[trial{:02d}] fidelity-1 : {:+.1e} dot=({:+.5f})'.format( i, abs(ip13) - 1, ip13))
def __init__(self, name: str, ansatz: VariationalAnsatz, hamiltonian: Union[openfermion.DiagonalCoulombHamiltonian, openfermion.FermionOperator, openfermion.InteractionOperator, openfermion.QubitOperator], preparation_circuit: Optional[cirq.Circuit] = None, datadir: Optional[str] = None) -> None: self.hamiltonian = hamiltonian if isinstance(hamiltonian, openfermion.QubitOperator): hamiltonian_qubit_op = hamiltonian else: hamiltonian_qubit_op = openfermion.jordan_wigner(hamiltonian) self._variance_bound = hamiltonian_qubit_op.induced_norm(order=1)**2 self._hamiltonian_linear_op = openfermion.LinearQubitOperator( hamiltonian_qubit_op) super().__init__(name, ansatz, preparation_circuit, datadir)
def one_particle_ucc(h, reference=1, trotter_order=1, trotter_steps=1): """ UCC-style ansatz preserving particle number. @author: Joel, Carl :param np.ndarray h: The hamiltonian matrix. :param int reference: the binary number corresponding to the reference state (which must be a Fock-state). :param int trotter_order: trotter order in suzuki_trotter :param int trotter_steps: trotter steps in suzuki_trotter :return: function(theta) which returns the ansatz Program """ dim = h.shape[0] terms = [] for occupied in range(dim): if reference & (1 << occupied): for unoccupied in range(dim): if not reference & (1 << unoccupied): term = FermionOperator(((unoccupied, 1), (occupied, 0))) \ - FermionOperator(((occupied, 1), (unoccupied, 0))) terms.append(qubitop_to_pyquilpauli(jordan_wigner(term))) exp_maps = trotterize(terms, trotter_order, trotter_steps) def wrap(theta): """ Returns the ansatz Program. :param np.ndarray theta: parameters :return: the Program :rtype: pyquil.Program """ prog = Program() for qubit in range(int.bit_length(reference)): if reference & (1 << qubit): prog += X(qubit) for idx, exp_map in enumerate(exp_maps): for exp in exp_map: prog += exp(theta[idx]) return prog return wrap
def test_rotorb_circuit(): import scipy.linalg np.set_printoptions(linewidth=300) N = 8 #k = np.random.rand(N,N) #k -= (k+k.T)/2 # random real antisymmetric matrix k = get_random_antihermite_mat(N) umat = scipy.linalg.expm(k) print(umat) c1 = OrbitalRotation(umat) from openfermion import FermionOperator, jordan_wigner, get_sparse_operator fop = FermionOperator() for p in range(N): for q in range(N): fop += FermionOperator(((p, 1), (q, 0)), k[p, q]) qop = jordan_wigner(fop) #print(qop) from trotter_qulacs import TrotterStep from util_qulacs import convert_state_vector M = 100 c2 = TrotterStep(N, qop / M) s1 = qulacs.QuantumState(N) s1.set_Haar_random_state() s2 = s1.copy() s3 = convert_state_vector(N, s1.get_vector()) c1._circuit.update_quantum_state(s1) for i in range(M): c2._circuit.update_quantum_state(s2) s3 = scipy.sparse.linalg.expm_multiply(get_sparse_operator(qop), s3) ip12 = qulacs.state.inner_product(s1, s2) ip13 = np.conjugate(convert_state_vector(N, s1.get_vector())).dot(s3) ip23 = np.conjugate(convert_state_vector(N, s2.get_vector())).dot(s3) print('dot(s1,s2)', abs(ip12), ip12) print('dot(s1,s3)', abs(ip13), ip13) print('dot(s2,s3)', abs(ip23), ip23)
def benchmark_molecular_operator_jordan_wigner(n_qubits): """Test speed with which molecular operators transform to qubit operators. Args: n_qubits: The size of the molecular operator instance. Ideally, we would be able to transform to a qubit operator for 50 qubit instances in less than a minute. We are way too slow right now. Returns: runtime: The number of seconds required to make the conversion. """ # Get an instance of InteractionOperator. molecular_operator = random_interaction_operator(n_qubits) # Convert to a qubit operator. start = time.time() _ = jordan_wigner(molecular_operator) end = time.time() # Return runtime. runtime = end - start return runtime
def get_hamiltonian_evaluation_operator(w: IWaveFunction) -> QubitOperator: molecule = w.molecule molecule.load() return jordan_wigner(molecule.get_molecular_hamiltonian())
def test_hubbard_model(abscissa: int, ordinate: int, tunneling: float, coulomb: float, magnetic_field: float, chemical_potential: float, periodic: bool, spinless: bool, symmetry: bool): hubbard_operator = fermi_hubbard( x_dimension=abscissa, y_dimension=ordinate, tunneling=tunneling, coulomb=coulomb, chemical_potential=chemical_potential, magnetic_field=magnetic_field, periodic=periodic, spinless=spinless, particle_hole_symmetry=symmetry ) # print(hubbard_operator) jw_hamiltonian = jordan_wigner(hubbard_operator) print('Jordan-Wigner hamiltonian without compression: ') print(jw_hamiltonian) print() jw_hamiltonian.compress() print('Jordan-Wigner hamiltonian with compression: ') print(jw_hamiltonian) print() sparse_operator = get_sparse_operator(hubbard_operator) print('Sparse operator') print(sparse_operator) print() print(f'Energy of the model is {get_ground_state(sparse_operator)[0]} in units of T and J') # xs = range(1, 9) # energy_levels = [ # get_ground_state( # get_sparse_operator( # fermi_hubbard( # x_dimension=x, # y_dimension=ordinate, # tunneling=tunneling, # coulomb=coulomb, # chemical_potential=chemical_potential, # magnetic_field=magnetic_field, # periodic=periodic, # spinless=spinless, # particle_hole_symmetry=symmetry # ) # ) # )[0] # for x in xs # ] # # os.makedirs('assets/hubbard', exist_ok=True) # # draw_plot( # xs, energy_levels, # x_label='X coordinate', # y_label='Ground state energy in units of T and J', # title='Ground state energy of the Hubbard model', # path='assets/hubbard/x.jpeg' # ) # # energy_levels = [ # get_ground_state( # get_sparse_operator( # fermi_hubbard( # x_dimension=abscissa, # y_dimension=x, # tunneling=tunneling, # coulomb=coulomb, # chemical_potential=chemical_potential, # magnetic_field=magnetic_field, # periodic=periodic, # spinless=spinless, # particle_hole_symmetry=symmetry # ) # ) # )[0] # for x in xs # ] # draw_plot( # xs, energy_levels, # x_label='Y coordinate', # y_label='Ground state energy in units of T and J', # title='Ground state energy of the Hubbard model', # path='assets/hubbard/y.jpeg' # ) ts = np.arange(0, 4, 0.2) energy_levels = [ get_ground_state( get_sparse_operator( fermi_hubbard( x_dimension=abscissa, y_dimension=ordinate, tunneling=t, coulomb=coulomb, chemical_potential=chemical_potential, magnetic_field=magnetic_field, periodic=periodic, spinless=spinless, particle_hole_symmetry=symmetry ) ) )[0] for t in ts ] draw_plot( ts, energy_levels, x_label='Tunneling coefficient', y_label='Ground state energy in units of T and J', title='Ground state energy of the Hubbard model', path='assets/hubbard/t.jpeg' )
def test_operators_initialization(coefficient: float): # 1. Let's create some basic operator operator = FermionOperator('2^ 1 3 7^', coefficient) alternative_operator = coefficient * FermionOperator(((2, 1), (1, 0), (3, 0), (6, 1))) sum_of_operators = operator + alternative_operator identity = FermionOperator('') zero = FermionOperator() # print(f'Fermion operator: {operator}; the terms are {list(operator.terms.keys())[0]}') print(f'Fermion operator: {operator}; the flattened terms are {operator.flattened_terms}') print(f'Alternative fermion operator: {alternative_operator}') print(f'Sum fermion operator: {sum_of_operators}; the terms are {sum_of_operators.terms}') # print(operator == alternative_operator) print(f'Identity operator: {identity}') print(f'Zero operator: {zero}') # 2. Checking operator combinations lhs_operator = FermionOperator('17^') rhs_operator = FermionOperator('19^') print(describe_result(lhs_operator, rhs_operator, lambda lhs, rhs: lhs * rhs, '*')) print(describe_result(lhs_operator, lhs_operator, lambda lhs, rhs: lhs * rhs, '*')) print(describe_result(lhs_operator, rhs_operator, lambda lhs, rhs: lhs + rhs, '+')) print(describe_result(lhs_operator, 5, lambda lhs, rhs: lhs ** rhs, '^')) # print(describe_result(lhs_operator * rhs_operator, lhs_operator, lambda lhs, rhs: lhs / rhs, '/')) # Throws an exception # 3. Use some auxiliary functions print(f'Operator {lhs_operator ** 5} occupies {count_qubits(lhs_operator)} qubits') print(f'Operator {rhs_operator ** 2} occupies {count_qubits(rhs_operator)} qubits') print(f'Operator {operator} occupies {count_qubits(operator)} qubits') print(f'Operator {operator} is {"not " if not operator.is_normal_ordered() else ""}normal ordered') print(f'Operator {(lhs_operator + rhs_operator)} is {"not " if not (lhs_operator + rhs_operator).is_normal_ordered() else ""}normal ordered') print(f'Operator {(lhs_operator * rhs_operator)} is {"not " if not (lhs_operator * rhs_operator).is_normal_ordered() else ""}normal ordered') print(f'Operator {(rhs_operator * lhs_operator)} is {"not " if not (rhs_operator * lhs_operator).is_normal_ordered() else ""}normal ordered') print(f'Commutator of {lhs_operator} and {rhs_operator} is {commutator(lhs_operator, rhs_operator)}') # 4. See qubit operators operator = QubitOperator('X1 Z3', coefficient) + QubitOperator('X20', coefficient - 1) print(f'Operator {operator} occupies {count_qubits(operator)} qubits') # 4. Perform transformations from fermion to qubit operators fermion_operator = FermionOperator_('5^', 0.1 + 0.2j) fermion_operator += hermitian_conjugated(fermion_operator) jw_operator = jordan_wigner(fermion_operator) bk_operator = bravyi_kitaev(fermion_operator) print() print('Source fermion operator:') print(fermion_operator) print() print('Source fermion operator with conjugate:') print(fermion_operator) print() print('Source fermion operator with conjugate passed through Jordan-Wigner transformation:') print(jw_operator) print() print('Eigenspectrum of the obtained operator:') print(eigenspectrum(jw_operator)) print() print('Reversed:') print(reverse_jordan_wigner(jw_operator)) print() print('Source fermion operator with conjugate passed through Bravyi-Kitaev transformation:') print(bk_operator) print() print('Eigenspectrum of the obtained operator:') print(eigenspectrum(bk_operator)) print()
def do_transform(self, fermion_operator: openfermion.FermionOperator, *args, **kwargs) -> openfermion.QubitOperator: return openfermion.jordan_wigner(fermion_operator, *args, **kwargs)
# dummy geometry geometry = [["Li", [0, 0, 0], ["H", [0, 0, 1.4]]]] charge = 0 multiplicity = 1 molecule = of.MolecularData( geometry=geometry, basis="sto-3g", charge=charge, multiplicity=multiplicity, ) molecule.one_body_integrals = h1e molecule.two_body_integrals = np.einsum("ijlk", -2 * h2e) molecular_hamiltonian = molecule.get_molecular_hamiltonian() molecular_hamiltonian.constant = 0 ham_fop = of.get_fermion_operator(molecular_hamiltonian) ham_mat = of.get_sparse_operator(of.jordan_wigner(ham_fop)).toarray() cirq_ci = fqe.to_cirq(wfn) cirq_ci = cirq_ci.reshape((2**12, 1)) assert np.isclose(cirq_ci.conj().T @ ham_mat @ cirq_ci, ecalc) hf_idx = int("111100000000", 2) hf_idx2 = int("111001000000", 2) hf_vec = np.zeros((2**12, 1)) hf_vec2 = np.zeros((2**12, 1)) hf_vec[hf_idx, 0] = 1.0 hf_vec2[hf_idx2, 0] = 1.0 # scale diagonal so vacuum has non-zero energy ww, vv = davidsonliu(ham_mat + np.eye(ham_mat.shape[0]), 1,
def test_trotterstep_circuit(self): from freqerica.op.symbol import WrappedExpr as Symbol from openfermion import FermionOperator, jordan_wigner, get_sparse_operator from sympy import Array import numpy as np np.random.seed(100) import scipy import qulacs n_orb = 2 const = Symbol('const') T1 = [[None for _ in range(n_orb)] for _ in range(n_orb)] for p in range(n_orb): for q in range(p, n_orb): t = Symbol('t{}{}'.format(p,q)) T1[p][q] = T1[q][p] = t T1 = Array(T1) print(T1) const_value = np.random.rand() T1_value = np.random.rand(n_orb,n_orb)*0.01 T1_value += T1_value.T print(const_value) print(T1_value) def op1e(const, Tmat): fop = FermionOperator('', const) for p in range(n_orb): for q in range(n_orb): fop += FermionOperator( ((2*p , 1),(2*q , 0)), Tmat[p,q] ) fop += FermionOperator( ((2*p+1, 1),(2*q+1, 0)), Tmat[p,q] ) return fop fop_symbol = op1e(const, T1) qop_symbol = jordan_wigner(fop_symbol) print(fop_symbol) print(qop_symbol) n_qubit = n_orb*2 # c1 : TrotterStep with symbolic qop c1 = freqerica.circuit.trotter.TrotterStep(n_qubit, (-1j)*qop_symbol) print(c1) symbol_number_pairs = [(const, const_value), (T1, T1_value)] c1.subs(symbol_number_pairs) print(c1) # c2 : TrotterStep with numerical qop fop_number = op1e(const_value, T1_value) qop_number = jordan_wigner(fop_number) c2 = freqerica.circuit.trotter.TrotterStep(n_qubit, (-1j)*qop_number) print(c2) # c3 : oldtype with numerical qop c3 = qulacs.QuantumCircuit(n_qubit) freqerica.circuit.trotter.trotter_step_2nd_order(c3, (-1j)*qop_number) s0 = qulacs.QuantumState(n_qubit) s0.set_Haar_random_state() s1 = s0.copy() s2 = s0.copy() s3 = s0.copy() from freqerica.util.qulacsnize import convert_state_vector sv = convert_state_vector( n_qubit, s0.get_vector() ) corr1 = [] corr2 = [] corr3 = [] corrv = [] for t in range(100): corr1.append( qulacs.state.inner_product(s0, s1) ) corr2.append( qulacs.state.inner_product(s0, s2) ) corr3.append( qulacs.state.inner_product(s0, s3)*np.exp(-1j*qop_number.terms[()]*t) ) corrv.append( np.dot(np.conjugate(convert_state_vector(n_qubit, s0.get_vector())), sv) ) c1._circuit.update_quantum_state(s1) c2._circuit.update_quantum_state(s2) c3.update_quantum_state(s3) sv = scipy.sparse.linalg.expm_multiply(-1j * get_sparse_operator(qop_number), sv)
ansatz = ansatz_1() init_qasm = None global_cache = GlobalCache(e_system, excited_state=0) global_cache.calculate_exc_gen_sparse_matrices_dict(ansatz) backend = MatrixCacheBackend optimizer = 'BFGS' optimizer_options = {'gtol': 10e-8, 'maxiter': 10} vqe_runner = VQERunner(e_system, backend=backend, print_var_parameters=False, use_ansatz_gradient=True, optimizer=optimizer, optimizer_options=optimizer_options) result = vqe_runner.vqe_run(ansatz=ansatz, cache=global_cache, init_state_qasm=init_qasm) parameters = result.x statevector = global_cache.get_statevector(ansatz, parameters, init_state_qasm=init_qasm) statevector = statevector.todense() operator = 'elenaananana' # TODO: TOVA trqbva da e klas openfermion.FermionicOperator operator = openfermion.jordan_wigner(operator) operator = openfermion.get_sparse_operator(operator, n_orbitals) expectation_value = statevector.dot(operator).dot(statevector.conj().transpose()) print(expectation_value) print('yolo')
def test_run_psi4( self, psi4_config: Psi4Config, expected_tuple: ExpectedTuple, jw_particle_num: Optional[int], ): results_dict = run_psi4( geometry=psi4_config.geometry, n_active_extract=psi4_config.n_active_extract, n_occupied_extract=psi4_config.n_occupied_extract, freeze_core=psi4_config.freeze_core, freeze_core_extract=psi4_config.freeze_core_extract, method=psi4_config.method, options=psi4_config.options, save_hamiltonian=True, save_rdms=psi4_config.save_rdms, ) results, hamiltonian, rdm = ( results_dict["results"], results_dict["hamiltonian"], results_dict["rdms"], ) if rdm: energy_from_rdm = rdm.expectation(hamiltonian) if psi4_config.save_rdms: assert math.isclose(results["energy"], energy_from_rdm) else: assert (math.isclose(results["energy"], expected_tuple.exp_energy) if expected_tuple.exp_energy else True) assert (results["n_alpha"] == expected_tuple.exp_alpha if expected_tuple.exp_alpha else True) assert (results["n_beta"] == expected_tuple.exp_beta if expected_tuple.exp_beta else True) assert (results["n_mo"] == expected_tuple.exp_mo if expected_tuple.exp_mo else True) assert (results["n_frozen_core"] == expected_tuple.exp_frozen_core if expected_tuple.exp_frozen_core else True) assert (results["n_frozen_valence"] == expected_tuple.exp_frozen_valence if expected_tuple.exp_frozen_valence else True) assert (hamiltonian.n_qubits == expected_tuple.exp_n_qubits if expected_tuple.exp_n_qubits else True) if expected_tuple.exp_one_body_tensor_shape: assert (rdm.one_body_tensor.shape[0] == expected_tuple.exp_one_body_tensor_shape) assert math.isclose(einsum("ii->", rdm.one_body_tensor), 2) if jw_particle_num: qubit_operator = qubit_operator_sparse(jordan_wigner(hamiltonian)) energy, _ = jw_get_ground_state_at_particle_number( qubit_operator, jw_particle_num) if expected_tuple.extra_energy_check: assert math.isclose(energy, expected_tuple.extra_energy_check, rel_tol=1e-7) else: assert math.isclose(energy, results["energy"], rel_tol=1e-7)
def observable_measurement(self) -> Tuple[Callable[[cirq.Circuit, Callable[[List[cirq.Qid]], List[cirq.Operation]], int], float], int]: """ Prepares an observable measurement function. Not yet general but specific for the H2 Hamiltonian objective. :return: Measurement function that: (Input) the circuit, ordered qubits and #measurement repetitions, (Output) expectation value. Also returns the circuit cost (number of circuits) required to calculate the expectation value. """ # Hamiltonian observable in the form of qubit operators. q_op = jordan_wigner(self.molecule.get_molecular_hamiltonian()) qubits = self.qubits # ordered_qubits pauli_term_size_lookup = {} pauli_weight_lookup = {} for term_pauli, term_weight in q_op.terms.items(): term_size = len(term_pauli) if term_size not in pauli_term_size_lookup: pauli_term_size_lookup[term_size] = [] # Set dictionaries pauli_term_size_lookup[term_size].append(term_pauli) pauli_weight_lookup[term_pauli] = term_weight def probability_to_expectation(probability: float, out: int): """ :param probability: Statistical probability [0, 1] corresponding to '0' output measurement. :param out: Whether to give information about the '0' or '1' output measurement. :return: Scaled measurement probability for either '0' or '1' output measurement in range [-1, 1]. """ if out == 0: return 2 * probability - 1 else: return 1 - 2 * probability def measure_observable(base_circuit: cirq.Circuit, noise_wrapper: Callable[[List[cirq.Qid]], List[cirq.Operation]], meas_reps: int) -> float: # , ordered_qubits: List[cirq.Qid] """ Constructs multiple quantum circuits to measure the expectation value of a given observable. :param base_circuit: Base circuit to measure (can be noisy) :param noise_wrapper: Noise wrapper function that generates single or two qubit noise operations :param meas_reps: Number of measurement repetitions for each circuit (higher means more accurate) [1, +inf). :return: (Approximation of) Hamiltonian observable expectation value. """ result = 0 basis_map = IGeneralizedUCCSD.pauli_basis_map() # Consistent qubit mapping labels = ['Z' + str(i) for i in range(len(qubits))] # Computational measurement labels simulator = cirq.DensityMatrixSimulator() expectation_lookup = QubitOperator(' ', 1.0) # Base term circuit_01 = base_circuit.copy() # Single pauli term measurement circuit for operator in pauli_term_size_lookup[1]: circuit_01.append([(basis_map[new_basis](qubits[qubit_id], 1), noise_wrapper(qubits[qubit_id])) for qubit_id, new_basis in operator]) circuit_01.append(cirq.measure(q, key=labels[i]) for i, q in enumerate(qubits)) circuit_01_shots = simulator.run(circuit_01, repetitions=meas_reps) # Single pauli terms for lb in labels: probability = circuit_01_shots.multi_measurement_histogram(keys=[lb])[(0,)] / meas_reps expectation = probability_to_expectation(probability, out=0) expectation_lookup += QubitOperator(lb, expectation) # Two pauli terms for operator_labels in itertools.combinations(labels, 2): probability = (circuit_01_shots.multi_measurement_histogram(keys=operator_labels)[(0, 0)] + circuit_01_shots.multi_measurement_histogram(keys=operator_labels)[(1, 1)]) / meas_reps expectation = probability_to_expectation(probability, out=0) expectation_lookup += QubitOperator(' '.join(operator_labels), expectation) # Four pauli terms for operator in pauli_term_size_lookup[4]: # Four pauli term measurement circuit operator_labels = [new_basis + str(qubit_id) for qubit_id, new_basis in operator] # Build circuit with basis transformation and measurement operators circuit_02 = base_circuit.copy() circuit_02.append([(basis_map[new_basis](qubits[qubit_id], 1), noise_wrapper(qubits[qubit_id])) for qubit_id, new_basis in operator]) circuit_02.append(cirq.measure(q, key=operator_labels[i]) for i, q in enumerate(qubits)) # Run measurement circuit_02_shots = simulator.run(circuit_02, repetitions=meas_reps) # Only equal parities probability = (circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(0, 0, 1, 1)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(1, 1, 0, 0)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(0, 1, 1, 0)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(1, 0, 1, 0)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(1, 0, 0, 1)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(0, 1, 0, 1)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(0, 0, 0, 0)] + circuit_02_shots.multi_measurement_histogram(keys=operator_labels)[(1, 1, 1, 1)]) / meas_reps expectation = probability_to_expectation(probability, out=0) expectation_lookup += QubitOperator(' '.join(operator_labels), expectation) # print(expectation_lookup) # Multiply hamiltonian term weights with circuit expectation values for each specific qubit operator set for operator in itertools.chain.from_iterable(pauli_term_size_lookup.values()): if operator in expectation_lookup.terms: result += pauli_weight_lookup[operator] * expectation_lookup.terms[operator] # print(f'Added {operator}(term): {pauli_weight_lookup[operator]}(weight) * {expectation_lookup.terms[operator]}(expectation) = {pauli_weight_lookup[operator] * expectation_lookup.terms[operator]}') return result return measure_observable, 5