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 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 test_erpa_eom_ham_h2(): filename = os.path.join(DATA_DIRECTORY, "H2_sto-3g_singlet_0.7414.hdf5") molecule = MolecularData(filename=filename) reduced_ham = make_reduced_hamiltonian( molecule.get_molecular_hamiltonian(), molecule.n_electrons) rha_fermion = of.get_fermion_operator(reduced_ham) permuted_hijkl = np.einsum('ijlk', reduced_ham.two_body_tensor) opdm = np.diag([1] * molecule.n_electrons + [0] * (molecule.n_qubits - molecule.n_electrons)) tpdm = 2 * of.wedge(opdm, opdm, (1, 1), (1, 1)) rdms = of.InteractionRDM(opdm, tpdm) dim = reduced_ham.one_body_tensor.shape[0] // 2 full_basis = {} # erpa basis. A, B basis in RPA language cnt = 0 for p, q in product(range(dim), repeat=2): if p < q: full_basis[(p, q)] = cnt full_basis[(q, p)] = cnt + dim * (dim - 1) // 2 cnt += 1 for rkey in full_basis.keys(): p, q = rkey for ckey in full_basis.keys(): r, s = ckey for sigma, tau in product([0, 1], repeat=2): test = erpa_eom_hamiltonian(permuted_hijkl, tpdm, 2 * q + sigma, 2 * p + sigma, 2 * r + tau, 2 * s + tau).real qp_op = of.FermionOperator( ((2 * q + sigma, 1), (2 * p + sigma, 0))) rs_op = of.FermionOperator( ((2 * r + tau, 1), (2 * s + tau, 0))) erpa_op = of.normal_ordered( of.commutator(qp_op, of.commutator(rha_fermion, rs_op))) true = rdms.expectation(of.get_interaction_operator(erpa_op)) assert np.isclose(true, test)
def apply_fermionic_constraints(interaction_operator: InteractionOperator, number_of_particles: int) -> None: fermion_operator = get_fermion_operator( load_interaction_operator(interaction_operator)) result = apply_constraints(fermion_operator, number_of_particles) save_interaction_operator(get_interaction_operator(result), "output_operator.json")
def do_transform(self, fermion_operator: openfermion.FermionOperator, *args, **kwargs) -> openfermion.QubitOperator: n_qubits = openfermion.count_qubits(fermion_operator) if n_qubits != self.n_orbitals * 2: raise Exception( "BravyiKitaevFast transformation currently only possible for full Hamiltonians (no UCC generators).\nfermion_operator was {}" .format(fermion_operator)) op = openfermion.get_interaction_operator(fermion_operator) return openfermion.bravyi_kitaev_fast(op)
def test_get_fermion_number_operator(self): # Given n_qubits = 4 n_particles = None correct_operator = get_interaction_operator( FermionOperator( """ 0.0 [] + 1.0 [0^ 0] + 1.0 [1^ 1] + 1.0 [2^ 2] + 1.0 [3^ 3] """ ) ) # When number_operator = get_fermion_number_operator(n_qubits) # Then self.assertEqual(number_operator, correct_operator) # Given n_qubits = 4 n_particles = 2 correct_operator = get_interaction_operator( FermionOperator( """ -2.0 [] + 1.0 [0^ 0] + 1.0 [1^ 1] + 1.0 [2^ 2] + 1.0 [3^ 3] """ ) ) # When number_operator = get_fermion_number_operator(n_qubits, n_particles) # Then self.assertEqual(number_operator, correct_operator)
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 test_interaction_op_to_dict_io(self): # Given test_op = FermionOperator("1^ 2^ 3 4") test_op += hermitian_conjugated(test_op) interaction_op = get_interaction_operator(test_op) interaction_op.constant = 0.0 # When interaction_op_dict = convert_interaction_op_to_dict(interaction_op) recreated_interaction_op = convert_dict_to_interaction_op( interaction_op_dict) # Then self.assertEqual(recreated_interaction_op, interaction_op)
def test_interaction_operator_io(self): # Given test_op = FermionOperator("1^ 2^ 3 4") test_op += hermitian_conjugated(test_op) interaction_op = get_interaction_operator(test_op) interaction_op.constant = 0.0 # When save_interaction_operator(interaction_op, "interaction_op.json") loaded_op = load_interaction_operator("interaction_op.json") # Then self.assertEqual(interaction_op, loaded_op) os.remove("interaction_op.json")
def get_fermion_number_operator(n_qubits, n_particles=None): """Return a FermionOperator representing the number operator for n qubits. If `n_particles` is specified, it can be used for creating constraint on the number of particles. Args: n_qubits (int): number of qubits in the system n_particles (int): number of particles in the system. If specified, it is substracted from the number operator such as expectation value is zero. Returns: (openfermion.ops.FermionOperator): the number operator """ operator = number_operator(n_qubits) if n_particles is not None: operator += FermionOperator("", -1.0 * float(n_particles)) return get_interaction_operator(operator)
def interaction_operator_generator( self, *, operator: Optional[openfermion.InteractionOperator] = None, modes: Optional[Sequence[int]] = None ) -> openfermion.InteractionOperator: """Constructs the Hamiltonian corresponding to the gate's generator.""" if modes is None: modes = tuple(range(self.num_qubits())) if operator is None: n_modes = max(modes) + 1 operator = openfermion.InteractionOperator.zero(n_modes) else: n_modes = operator.n_qubits fermion_operator = self.fermion_generator return openfermion.get_interaction_operator(fermion_operator, n_qubits=n_modes)
def remove_inactive_orbitals(interaction_op: InteractionOperator, n_active: int = None, n_core: int = 0) -> InteractionOperator: """Remove orbitals not in the active space from an interaction operator. Args: interaction_op: the operator, assumed to be ordered with alternating spin-up and spin-down spin orbitals. n_active: the number of active molecular orbitals. If None, include all orbitals beyond n_core. Note that the number of active spin orbitals will be twice the number of active molecular orbitals. n_core: the number of core molecular orbitals to be frozen. Returns: The interaction operator with inactive orbitals removed, and the Hartree-Fock energy of the core orbitals added to the constant. """ # This implementation is probably not very efficient, because it converts the # interaction operator into a fermion operator and then back to an interaction # operator. # Convert the InteractionOperator to a FermionOperator fermion_op = get_fermion_operator(interaction_op) # Determine which occupied spin-orbitals are to be frozen occupied = range(2 * n_core) unoccupied: Iterable # Determine which unoccupied spin-orbitals are to be frozen if n_active is not None: unoccupied = range(2 * n_core + 2 * n_active, interaction_op.one_body_tensor.shape[0]) else: unoccupied = [] # Freeze the spin-orbitals frozen_fermion_op = freeze_orbitals(fermion_op, occupied, unoccupied) # Convert back to an interaction operator frozen_interaction_op = get_interaction_operator(frozen_fermion_op) return frozen_interaction_op
def v2rdm_hubbard_open_shell(): import openfermion as of e_fci = [] e_rdm = [] for U in [1]: # range(1, 11): sites = 5 hubbard = of.hamiltonians.fermi_hubbard(1, sites, tunneling=1, coulomb=U, chemical_potential=0, magnetic_field=0, periodic=True, spinless=False) hamiltonian = of.get_interaction_operator(hubbard) op_mat = of.get_number_preserving_sparse_operator( hubbard, 2 * sites, sites, spin_preserving=True).toarray() sz_mat = of.get_number_preserving_sparse_operator( of.sz_operator(sites), 2 * sites, sites, spin_preserving=True).toarray() s2_mat = of.get_number_preserving_sparse_operator( of.s_squared_operator(sites), 2 * sites, sites, spin_preserving=True).toarray() w, v = np.linalg.eigh(op_mat) sz_exp = [] s2_exp = [] for ii in range(len(w)): sz_exp.append((v[:, [ii]].conj().T @ sz_mat @ v[:, [ii]])[0, 0].real) s2_exp.append((v[:, [ii]].conj().T @ s2_mat @ v[:, [ii]])[0, 0].real) print(sz_exp[:10]) print(s2_exp[:10]) print(w[:10]) gs_e = w[0] print(gs_e) one_body_ints, two_body_ints = hamiltonian.one_body_tensor, hamiltonian.two_body_tensor two_body_ints = np.einsum('ijkl->ijlk', two_body_ints) n_electrons = sites print('n_electrons', n_electrons) Na = 1 + (n_electrons // 2) Nb = n_electrons // 2 spatial_basis_rank = sites bij_bas_aa, bij_bas_ab = geminal_spin_basis(spatial_basis_rank) opdm_a_interaction, opdm_b_interaction, v2aa, v2bb, v2ab = \ spin_adapted_interaction_tensor_rdm_consistent(two_body_ints.real, one_body_ints.real) v2ab_mat = np.zeros_like(v2ab.data) for i in range(spatial_basis_rank): # ia^ j^b j^b ia idx = bij_bas_ab.rev((i, i)) v2ab_mat[idx, idx] = U v2ab = Tensor(v2ab_mat, basis=v2ab.basis, name=v2ab.name) dual_basis = sz_adapted_linear_constraints( spatial_basis_rank, Na, Nb, ['ck', 'cckk', 'kkcc', 'ckck'], S=0.5, M=0.5) print("constructed dual basis") copdm_a = opdm_a_interaction copdm_b = opdm_b_interaction coqdm_a = Tensor(np.zeros((spatial_basis_rank, spatial_basis_rank)), name='kc_a') coqdm_b = Tensor(np.zeros((spatial_basis_rank, spatial_basis_rank)), name='kc_b') ctpdm_aa = v2aa ctpdm_bb = v2bb ctpdm_ab = v2ab ctqdm_aa = Tensor(np.zeros_like(v2aa.data), name='kkcc_aa', basis=bij_bas_aa) ctqdm_bb = Tensor(np.zeros_like(v2bb.data), name='kkcc_bb', basis=bij_bas_aa) ctqdm_ab = Tensor(np.zeros_like(v2ab.data), name='kkcc_ab', basis=bij_bas_ab) cphdm_ab = Tensor(np.zeros((spatial_basis_rank * spatial_basis_rank, spatial_basis_rank * spatial_basis_rank)), name='ckck_ab', basis=bij_bas_ab) cphdm_ba = Tensor(np.zeros((spatial_basis_rank * spatial_basis_rank, spatial_basis_rank * spatial_basis_rank)), name='ckck_ba', basis=bij_bas_ab) cphdm_aabb = Tensor(np.zeros( (2 * spatial_basis_rank**2, 2 * spatial_basis_rank**2)), name='ckck_aabb') ctensor = MultiTensor([ copdm_a, copdm_b, coqdm_a, coqdm_b, ctpdm_aa, ctpdm_bb, ctpdm_ab, ctqdm_aa, ctqdm_bb, ctqdm_ab, cphdm_ab, cphdm_ba, cphdm_aabb ]) ctensor.dual_basis = dual_basis A, _, b = ctensor.synthesize_dual_basis() print("size of dual basis", len(dual_basis.elements)) nc, nv = A.shape nnz = A.nnz sdp = SDP() sdp.nc = nc sdp.nv = nv sdp.nnz = nnz sdp.blockstruct = list( map(lambda x: int(np.sqrt(x.size)), ctensor.tensors)) sdp.nb = len(sdp.blockstruct) sdp.Amat = A.real sdp.bvec = b.todense().real sdp.cvec = ctensor.vectorize_tensors().real sdp.Initialize() epsilon = 0.5e-5 sdp.epsilon = float(epsilon) sdp.epsilon_inner = float(epsilon) sdp.disp = True sdp.iter_max = 50000 sdp.inner_iter_max = 1 sdp.inner_solve = 'CG' sdp_data = solve_bpsdp(sdp) print(sdp.primal.T @ sdp.cvec, gs_e)
def v2rdm_hubbard(): import sys from openfermion.hamiltonians import MolecularData from openfermionpsi4 import run_psi4 from openfermionpyscf import run_pyscf from openfermion.utils import map_one_pdm_to_one_hole_dm, \ map_two_pdm_to_two_hole_dm, map_two_pdm_to_particle_hole_dm import openfermion as of e_fci = [] e_rdm = [] for U in [4]: # range(1, 11): sites = 5 hubbard = of.hamiltonians.fermi_hubbard(1, sites, tunneling=1, coulomb=U, chemical_potential=0, magnetic_field=0, periodic=True, spinless=False) # op_mat = of.get_sparse_operator(hubbard).toarray() # # op_mat = of.get_number_preserving_sparse_operator(hubbard, sites * 2, sites-1).toarray() # w, v = np.linalg.eigh(op_mat) # # w_idx = 5 # N4U4 # # w_idx = 25 # N6 U4 # w_idx = 4 # n_density = v[:, [w_idx]] @ v[:, [w_idx]].conj().T # from representability.fermions.density.antisymm_sz_density import AntiSymmOrbitalDensity # density = AntiSymmOrbitalDensity(n_density, sites * 2) # tpdm_aa, tpdm_bb, tpdm_ab, [bas_aa, bas_ab] = density.construct_tpdm() # rev_bas_aa = dict(zip(bas_aa.values(), bas_aa.keys())) # rev_bas_ab = dict(zip(bas_ab.values(), bas_ab.keys())) # for r, s in product(range(sites), repeat=2): # i, j = rev_bas_ab[r] # k, l = rev_bas_ab[s] # tqdm_aa, tqdm_bb, tqdm_ab, _ = density.construct_thdm() # phdm_ab, phdm_ba, phdm_aabb = density.construct_phdm() # opdm_a, opdm_b = density.construct_opdm() # bas_aa, bas_ab = geminal_spin_basis(sites) # opdm_a = Tensor(opdm_a, name='ck_a') # opdm_b = Tensor(opdm_b, name='ck_b') # oqdm_a = Tensor(np.eye(4) - opdm_a.data, name='kc_a') # oqdm_b = Tensor(np.eye(4) - opdm_b.data, name='kc_b') # tpdm_aa = Tensor(tpdm_aa, name='cckk_aa', basis=bas_aa) # tpdm_bb = Tensor(tpdm_bb, name='cckk_bb', basis=bas_aa) # tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab) # tqdm_aa = Tensor(tqdm_aa, name='kkcc_aa', basis=bas_aa) # tqdm_bb = Tensor(tqdm_bb, name='kkcc_bb', basis=bas_aa) # tqdm_ab = Tensor(tqdm_ab, name='kkcc_ab', basis=bas_ab) # phdm_ab = Tensor(phdm_ab, name='ckck_ab', basis=bas_ab) # phdm_ba = Tensor(phdm_ba, name='ckck_ba', basis=bas_ab) # phdm_aabb = Tensor(phdm_aabb, name='ckck_aabb') # rdms = MultiTensor( # [opdm_a, opdm_b, oqdm_a, oqdm_b, # tpdm_aa, tpdm_bb, tpdm_ab, # tqdm_aa, tqdm_bb, tqdm_ab, # phdm_ab, phdm_ba, phdm_aabb]) # rdmvec = rdms.vectorize_tensors() hamiltonian = of.get_interaction_operator(hubbard) op_mat = of.get_number_preserving_sparse_operator( hubbard, 2 * sites, sites - 1, spin_preserving=False).toarray() w, _ = np.linalg.eigh(op_mat) gs_e = w[0] print(gs_e) one_body_ints, two_body_ints = hamiltonian.one_body_tensor, hamiltonian.two_body_tensor two_body_ints = np.einsum('ijkl->ijlk', two_body_ints) n_electrons = sites - 1 print('n_electrons', n_electrons) Na = n_electrons // 2 Nb = n_electrons // 2 dim = one_body_ints.shape[0] spatial_basis_rank = sites sdim = spatial_basis_rank mm = dim**2 bij_bas_aa, bij_bas_ab = geminal_spin_basis(spatial_basis_rank) # h1, v2 = spin_orbital_interaction_tensor(two_body_ints, one_body_ints) opdm_a_interaction, opdm_b_interaction, v2aa, v2bb, v2ab = \ spin_adapted_interaction_tensor_rdm_consistent(two_body_ints.real, one_body_ints.real) v2ab_mat = np.zeros_like(v2ab.data) for i in range(spatial_basis_rank): # ia^ j^b j^b ia idx = bij_bas_ab.rev((i, i)) v2ab_mat[idx, idx] = U v2ab = Tensor(v2ab_mat, basis=v2ab.basis, name=v2ab.name) dual_basis = sz_adapted_linear_constraints( spatial_basis_rank, Na, Nb, ['ck', 'cckk', 'kkcc', 'ckck']) print("constructed dual basis") copdm_a = opdm_a_interaction copdm_b = opdm_b_interaction coqdm_a = Tensor(np.zeros((spatial_basis_rank, spatial_basis_rank)), name='kc_a') coqdm_b = Tensor(np.zeros((spatial_basis_rank, spatial_basis_rank)), name='kc_b') ctpdm_aa = v2aa ctpdm_bb = v2bb ctpdm_ab = v2ab ctqdm_aa = Tensor(np.zeros_like(v2aa.data), name='kkcc_aa', basis=bij_bas_aa) ctqdm_bb = Tensor(np.zeros_like(v2bb.data), name='kkcc_bb', basis=bij_bas_aa) ctqdm_ab = Tensor(np.zeros_like(v2ab.data), name='kkcc_ab', basis=bij_bas_ab) cphdm_ab = Tensor(np.zeros((spatial_basis_rank * spatial_basis_rank, spatial_basis_rank * spatial_basis_rank)), name='ckck_ab', basis=bij_bas_ab) cphdm_ba = Tensor(np.zeros((spatial_basis_rank * spatial_basis_rank, spatial_basis_rank * spatial_basis_rank)), name='ckck_ba', basis=bij_bas_ab) cphdm_aabb = Tensor(np.zeros( (2 * spatial_basis_rank**2, 2 * spatial_basis_rank**2)), name='ckck_aabb') ctensor = MultiTensor([ copdm_a, copdm_b, coqdm_a, coqdm_b, ctpdm_aa, ctpdm_bb, ctpdm_ab, ctqdm_aa, ctqdm_bb, ctqdm_ab, cphdm_ab, cphdm_ba, cphdm_aabb ]) ctensor.dual_basis = dual_basis A, _, b = ctensor.synthesize_dual_basis() print("size of dual basis", len(dual_basis.elements)) # print(tpdm_ab.data.trace()) # print(ctensor.vectorize_tensors().T @ rdmvec) # print(b.shape) # print("FCI Residual ", np.linalg.norm(A @ rdmvec - b)) # exit() nc, nv = A.shape # A.eliminate_zeros() nnz = A.nnz sdp = SDP() sdp.nc = nc sdp.nv = nv sdp.nnz = nnz sdp.blockstruct = list( map(lambda x: int(np.sqrt(x.size)), ctensor.tensors)) sdp.nb = len(sdp.blockstruct) sdp.Amat = A.real sdp.bvec = b.todense().real sdp.cvec = ctensor.vectorize_tensors().real Amat = A.toarray() # print(A.shape) # # DQ num vars: 4, 4, 4, 4, 6, 6, 16, 6, 6 16 # print("D2 size ", sum([x**2 for x in [6, 6, 16]])) # print("D1Q1 size ", sum([x**2 for x in [4, 4, 4, 4]])) # print("Spin constraint ", 16**2) # print(sum([x**2 for x in [4, 4, 4, 4, 6, 6, 16, 16]])) sm = sdim * (sdim - 1) // 2 uadapt = gen_trans_2rdm(sdim**2, sdim) # spin_adapted_d2ab = uadapt.T @ tpdm_ab.data @ uadapt # d2ab_sa_a = spin_adapted_d2ab[:sm, :sm] # d2ab_sa_s = spin_adapted_d2ab[sm:, sm:] # for r, s in product(range(sdim * (sdim - 1) // 2), repeat=2): # i, j = bas_aa.fwd(r) # k, l = bas_aa.fwd(s) # # print((i, j, k, l), d2ab_sa_a[bas_aa.rev((i, j)), bas_aa.rev((k, l))], # # uadapt[:, r].T @ tpdm_ab.data @ uadapt[:, s] # # ) # assert np.isclose(d2ab_sa_a[bas_aa.rev((i, j)), bas_aa.rev((k, l))], uadapt[:, [r]].T @ tpdm_ab.data @ uadapt[:, [s]]) # assert np.isclose(d2ab_sa_a[bas_aa.rev((i, j)), bas_aa.rev((k, l))], np.trace(tpdm_ab.data @ (uadapt[:, [s]] @ uadapt[:, [r]].T))) # assert np.isclose(d2ab_sa_a[bas_aa.rev((i, j)), bas_aa.rev((k, l))], np.einsum('ij,ij', tpdm_ab.data, (uadapt[:, [s]] @ uadapt[:, [r]].T))) # assert np.isclose(tpdm_aa.data[r, s] + tpdm_aa.data[s, r], uadapt[:, [r]].T @ tpdm_ab.data @ uadapt[:, [s]] + uadapt[:, [s]].T @ tpdm_ab.data @ uadapt[:, [r]]) # assert np.isclose(tpdm_bb.data[r, s] + tpdm_bb.data[s, r], uadapt[:, [r]].T @ tpdm_ab.data @ uadapt[:, [s]] + uadapt[:, [s]].T @ tpdm_ab.data @ uadapt[:, [r]]) print("AA Dim: ", sdim * (sdim - 1) / 2, sm * (sm + 1) / 2) for ii in range(Amat.shape[0]): amats = vec2block(sdp.blockstruct, Amat[ii, :]) for aa in amats: assert of.is_hermitian(aa) sdp.Initialize() epsilon = 1.0E-6 sdp.epsilon = float(epsilon) sdp.epsilon_inner = float(epsilon) sdp.disp = True sdp.iter_max = 50000 sdp.inner_iter_max = 1 sdp.inner_solve = 'CG' write_sdpfile("new_hubbardN{}U{}_DQG.sdp".format(sites, U), sdp.nc, sdp.nv, sdp.nnz, sdp.nb, sdp.Amat, sdp.bvec, sdp.cvec, sdp.blockstruct) # sdp_data = solve_bpsdp(sdp) # sdp_data.primal_vector = rdmvec # sdp.iter_max = 5000 # sdp_data = solve_bpsdp(sdp) solve_rrsdp(sdp) print(sdp.primal.T @ sdp.cvec, gs_e)