コード例 #1
0
 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))
コード例 #2
0
 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)
コード例 #3
0
 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))
コード例 #4
0
 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))
コード例 #5
0
 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))
コード例 #6
0
 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))
コード例 #7
0
    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)
コード例 #8
0
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
コード例 #9
0
    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
コード例 #10
0
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
コード例 #11
0
 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