def test_get_interaction_operator_one_body(self): interaction_operator = get_interaction_operator( FermionOperator('2^ 2'), self.n_qubits) one_body = numpy.zeros((self.n_qubits, self.n_qubits), float) one_body[2, 2] = 1. self.assertEqual(interaction_operator, InteractionOperator(0.0, one_body, self.two_body))
def setUp(self): self.n_qubits = 5 self.constant = 0. self.one_body = numpy.zeros((self.n_qubits, self.n_qubits), float) self.two_body = numpy.zeros( (self.n_qubits, self.n_qubits, self.n_qubits, self.n_qubits), float) self.interaction_operator = InteractionOperator( self.constant, self.one_body, self.two_body)
def test_get_interaction_operator_two_body_distinct(self): interaction_operator = get_interaction_operator( FermionOperator('0^ 1^ 2 3'), self.n_qubits) two_body = numpy.zeros( (self.n_qubits, self.n_qubits, self.n_qubits, self.n_qubits), float) two_body[1, 0, 3, 2] = 1. self.assertEqual(interaction_operator, InteractionOperator(0.0, self.one_body, two_body))
def test_get_interaction_operator_two_body(self): interaction_operator = get_interaction_operator( FermionOperator('2^ 2 3^ 4'), self.n_qubits) two_body = numpy.zeros( (self.n_qubits, self.n_qubits, self.n_qubits, self.n_qubits), float) two_body[3, 2, 4, 2] = -1. self.assertEqual(interaction_operator, InteractionOperator(0.0, self.one_body, two_body))
def test_get_interaction_operator_one_body_twoterm(self): interaction_operator = get_interaction_operator( FermionOperator('2^ 3', -2j) + FermionOperator('3^ 2', 3j), self.n_qubits) one_body = numpy.zeros((self.n_qubits, self.n_qubits), complex) one_body[2, 3] = -2j one_body[3, 2] = 3j self.assertEqual(interaction_operator, InteractionOperator(0.0, one_body, self.two_body))
def test_get_interaction_operator_identity(self): interaction_operator = InteractionOperator(-2j, self.one_body, self.two_body) qubit_operator = jordan_wigner(interaction_operator) self.assertTrue(qubit_operator.isclose(-2j * QubitOperator(()))) self.assertEqual( interaction_operator, get_interaction_operator(reverse_jordan_wigner(qubit_operator), self.n_qubits))
def test_four_point_iter(self): constant = 100.0 one_body = numpy.zeros((self.n_qubits, self.n_qubits), float) two_body = numpy.zeros( (self.n_qubits, self.n_qubits, self.n_qubits, self.n_qubits), float) one_body[1, 1] = 10.0 one_body[2, 3] = 11.0 one_body[3, 2] = 11.0 two_body[1, 2, 3, 4] = 12.0 two_body[2, 1, 4, 3] = 12.0 two_body[3, 4, 1, 2] = 12.0 two_body[4, 3, 2, 1] = 12.0 interaction_operator = InteractionOperator(constant, one_body, two_body) want_str = '100.0\n10.0\n11.0\n12.0\n' got_str = '' for key in interaction_operator.unique_iter(complex_valued=True): got_str += '{}\n'.format(interaction_operator[key]) self.assertEqual(want_str, got_str)
def artificial_molecular_operator(n_qubits): """Make an artificial random InteractionOperator for testing purposes.""" # Initialize. constant = numpy.random.randn() one_body_coefficients = numpy.zeros((n_qubits, n_qubits), float) two_body_coefficients = numpy.zeros( (n_qubits, n_qubits, n_qubits, n_qubits), float) # Randomly generate the one-body and two-body integrals. for p in range(n_qubits): for q in range(n_qubits): # One-body terms. if (p <= p) and (p % 2 == q % 2): one_body_coefficients[p, q] = numpy.random.randn() one_body_coefficients[q, p] = one_body_coefficients[p, q] # Keep looping. for r in range(n_qubits): for s in range(n_qubits): # Skip zero terms. if (p == q) or (r == s): continue # Identify and skip one of the complex conjugates. if [p, q, r, s] != [s, r, q, p]: unique_indices = len(set([p, q, r, s])) # srqp srpq sprq spqr sqpr sqrp # rsqp rspq rpsq rpqs rqps rqsp. if unique_indices == 4: if min(r, s) <= min(p, q): continue # qqpp. elif unique_indices == 2: if q < p: continue # Add the two-body coefficients. two_body_coefficients[p, q, r, s] = numpy.random.randn() two_body_coefficients[s, r, q, p] = two_body_coefficients[p, q, r, s] # Build the molecular operator and return. molecular_operator = InteractionOperator(constant, one_body_coefficients, two_body_coefficients) return molecular_operator
def get_molecular_hamiltonian(self, occupied_indices=None, active_indices=None): """Output arrays of the second quantized Hamiltonian coefficients. Args: rotation_matrix: A square numpy array or matrix having dimensions of n_orbitals by n_orbitals. Assumed real and invertible. occupied_indices(list): A list of spatial orbital indices indicating which orbitals should be considered doubly occupied. active_indices(list): A list of spatial orbital indices indicating which orbitals should be considered active. Returns: molecular_hamiltonian: An instance of the MolecularOperator class. """ # Get active space integrals. if occupied_indices is None and active_indices is None: one_body_integrals, two_body_integrals = self.get_integrals() constant = self.nuclear_repulsion else: core_adjustment, one_body_integrals, two_body_integrals = self.\ get_active_space_integrals(occupied_indices, active_indices) constant = self.nuclear_repulsion + core_adjustment n_qubits = 2 * one_body_integrals.shape[0] # Initialize Hamiltonian coefficients. one_body_coefficients = numpy.zeros((n_qubits, n_qubits)) two_body_coefficients = numpy.zeros( (n_qubits, n_qubits, n_qubits, n_qubits)) # Loop through integrals. for p in range(n_qubits // 2): for q in range(n_qubits // 2): # Populate 1-body coefficients. Require p and q have same spin. one_body_coefficients[2 * p, 2 * q] = one_body_integrals[p, q] one_body_coefficients[2 * p + 1, 2 * q + 1] = one_body_integrals[p, q] # Continue looping to prepare 2-body coefficients. for r in range(n_qubits // 2): for s in range(n_qubits // 2): # Require p,s and q,r to have same spin. Handle mixed # spins. two_body_coefficients[2 * p, 2 * q + 1, 2 * r + 1, 2 * s] = (two_body_integrals[p, q, r, s] / 2.) two_body_coefficients[2 * p + 1, 2 * q, 2 * r, 2 * s + 1] = (two_body_integrals[p, q, r, s] / 2.) # Avoid having two electrons in same orbital. Handle # same spins. if p != q and r != s: two_body_coefficients[ 2 * p, 2 * q, 2 * r, 2 * s] = (two_body_integrals[p, q, r, s] / 2.) two_body_coefficients[ 2 * p + 1, 2 * q + 1, 2 * r + 1, 2 * s + 1] = (two_body_integrals[p, q, r, s] / 2.) # Truncate. one_body_coefficients[ numpy.absolute(one_body_coefficients) < EQ_TOLERANCE] = 0. two_body_coefficients[ numpy.absolute(two_body_coefficients) < EQ_TOLERANCE] = 0. # Cast to InteractionOperator class and return. molecular_hamiltonian = InteractionOperator(constant, one_body_coefficients, two_body_coefficients) return molecular_hamiltonian
def get_interaction_operator(fermion_operator, n_qubits=None): """Convert a 2-body fermionic operator to InteractionOperator. This function should only be called on fermionic operators which consist of only a_p^\dagger a_q and a_p^\dagger a_q^\dagger a_r a_s terms. The one-body terms are stored in a matrix, one_body[p, q], and the two-body terms are stored in a tensor, two_body[p, q, r, s]. Returns: interaction_operator: An instance of the InteractionOperator class. Raises: TypeError: Input must be a FermionOperator. TypeError: FermionOperator does not map to InteractionOperator. Warning: Even assuming that each creation or annihilation operator appears at most a constant number of times in the original operator, the runtime of this method is exponential in the number of qubits. """ if not isinstance(fermion_operator, FermionOperator): raise TypeError('Input must be a FermionOperator.') if n_qubits is None: n_qubits = count_qubits(fermion_operator) if n_qubits < count_qubits(fermion_operator): n_qubits = count_qubits(fermion_operator) # Normal order the terms and initialize. fermion_operator = normal_ordered(fermion_operator) constant = 0. one_body = numpy.zeros((n_qubits, n_qubits), complex) two_body = numpy.zeros((n_qubits, n_qubits, n_qubits, n_qubits), complex) # Loop through terms and assign to matrix. for term in fermion_operator.terms: coefficient = fermion_operator.terms[term] # Handle constant shift. if len(term) == 0: constant = coefficient elif len(term) == 2: # Handle one-body terms. if [operator[1] for operator in term] == [1, 0]: p, q = [operator[0] for operator in term] one_body[p, q] = coefficient else: raise InteractionOperatorError('FermionOperator does not map ' 'to InteractionOperator.') elif len(term) == 4: # Handle two-body terms. if [operator[1] for operator in term] == [1, 1, 0, 0]: p, q, r, s = [operator[0] for operator in term] two_body[p, q, r, s] = coefficient else: raise InteractionOperatorError('FermionOperator does not map ' 'to InteractionOperator.') else: # Handle non-molecular Hamiltonian. raise InteractionOperatorError('FermionOperator does not map ' 'to InteractionOperator.') # Form InteractionOperator and return. interaction_operator = InteractionOperator(constant, one_body, two_body) return interaction_operator
def load(self): geometry = [] with h5py.File("{}.hdf5".format(self.filename), "r") as f: # Load geometry: for atom, pos in zip(f["geometry/atoms"][...], f["geometry/positions"][...]): geometry.append((str(atom), list(pos))) self.geometry = geometry # Load basis: self.basis = str(f["basis"][...]) # Load multiplicity: self.multiplicity = int(f["multiplicity"][...]) # Load charge: self.charge = int(f["charge"][...]) # Load description: self.description = str(f["description"][...]) # Load name: self.name = str(f["name"][...]) # Load n_atoms: self.n_atoms = int(f["n_atoms"][...]) # Load atoms: self.atoms = f["atoms"][...] # Load protons: self.protons = f["protons"][...] # Load n_electrons: self.n_electrons = int(f["n_electrons"][...]) # Load generic attributes from calculations: d_0 = f["n_orbitals"][...] self.n_orbitals = int(d_0) if d_0.dtype.num != 0 else None d_1 = f["n_qubits"][...] self.n_qubits = int(d_1) if d_1.dtype.num != 0 else None d_2 = f["nuclear_repulsion"][...] self.nuclear_repulsion = float(d_2) if d_2.dtype.num != 0 else None # Load attributes generated from SCF calculation. d_3 = f["hf_energy"][...] self.hf_energy = d_3 if d_3.dtype.num != 0 else None d_4 = f["canonical_orbitals"][...] self.canonical_orbitals = d_4 if d_4.dtype.num != 0 else None d_5 = f["orbital_energies"][...] self.orbital_energies = d_5 if d_5.dtype.num != 0 else None # Load attributes generated from integrals. d_6 = f["orbital_overlaps"][...] self.orbital_overlaps = d_6 if d_6.dtype.num != 0 else None d_7 = f["one_body_integrals"][...] self.one_body_integrals = d_7 if d_7.dtype.num != 0 else None # Load attributes generated from MP2 calculation. d_8 = f["mp2_energy"][...] self.mp2_energy = d_8 if d_8.dtype.num != 0 else None # Load attributes generated from CISD calculation. d_9 = f["cisd_energy"][...] self.cisd_energy = d_9 if d_9.dtype.num != 0 else None d_10 = f["cisd_one_rmd"][...] self.cisd_one_rdm = d_10 if d_10.dtype.num != 0 else None # Load attributes generated from exact diagonalization. d_11 = f["fci_energy"][...] self.fci_energy = d_11 if d_11.dtype.num != 0 else None d_12 = f["fci_one_rdm"][...] self.fci_one_rdm = d_12 if d_12.dtype.num != 0 else None # Load attributes generated from CCSD calculation. d_13 = f["ccsd_energy"][...] self.ccsd_energy = d_13 if d_13.dtype.num != 0 else None if f["ccsd_amplitudes/constant"][...].dtype.num != 0: constant = f["ccsd_amplitudes/constant"][...] one = f["ccsd_amplitudes/one_body_tensor"][...] two = f["ccsd_amplitudes/two_body_tensor"][...] self.ccsd_amplitudes = InteractionOperator(constant, one, two) else: self.ccsd_amplitudes = None