def test_building_hamiltonian(
    charge, mult, package, nact_els, nact_orbs, mapping, psi4_support, requires_babel, tmpdir,
):
    r"""Test that the generated Hamiltonian `built_hamiltonian` is an instance of the PennyLane
    Hamiltonian class and the correctness of the total number of qubits required to run the
    quantum simulation. The latter is tested for different values of the molecule's charge and
    for active spaces with different size"""

    if package == "psi4" and not psi4_support:
        pytest.skip("Skipped, no Psi4 support")

    built_hamiltonian, qubits = qchem.molecular_hamiltonian(
        symbols,
        coordinates,
        charge=charge,
        mult=mult,
        package=package,
        active_electrons=nact_els,
        active_orbitals=nact_orbs,
        mapping=mapping,
        outpath=tmpdir.strpath,
    )

    assert isinstance(built_hamiltonian, Hamiltonian)
    assert qubits == 2 * nact_orbs
def decompose(name, geometry, charge, multiplicity, basis_set):
    decomp, qubit_num = qchem.molecular_hamiltonian(name,
                                                    geometry,
                                                    charge=charge,
                                                    mult=multiplicity,
                                                    basis=basis_set,
                                                    active_electrons=2,
                                                    active_orbitals=2,
                                                    mapping='jordan_wigner')

    coefficients, observables = decomp.terms
    observables = [[group for group in zip(term.name, term.wires)]
                   for term in observables]

    return coefficients, observables, qubit_num
Example #3
0
def test_qchem_expvalcost_correct(r_dtype, c_dtype):
    """EvpvalCost with qchem Hamiltonian work corectly"""
    from pennylane import qchem

    symbols = ["Li", "H"]
    geometry = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 2.969280527])
    H, qubits = qchem.molecular_hamiltonian(symbols,
                                            geometry,
                                            active_electrons=2,
                                            active_orbitals=5)
    active_electrons = 2
    hf_state = qchem.hf_state(active_electrons, qubits)

    def circuit_1(params, wires):
        qml.BasisState(hf_state, wires=wires)
        qml.RX(params[0], wires=0)
        qml.RY(params[0], wires=1)
        qml.RZ(params[0], wires=2)
        qml.Hadamard(wires=1)

    diff_method = "adjoint"
    dev_lig = qml.device("lightning.qubit", wires=qubits, c_dtype=c_dtype)
    cost_fn_lig = qml.ExpvalCost(circuit_1,
                                 H,
                                 dev_lig,
                                 optimize=False,
                                 diff_method=diff_method)
    circuit_gradient_lig = qml.grad(cost_fn_lig, argnum=0)
    params = np.array([0.123], requires_grad=True)
    grads_lig = circuit_gradient_lig(params)

    dev_def = qml.device("default.qubit", wires=qubits)
    cost_fn_def = qml.ExpvalCost(circuit_1,
                                 H,
                                 dev_def,
                                 optimize=False,
                                 diff_method=diff_method)
    circuit_gradient_def = qml.grad(cost_fn_def, argnum=0)
    params = np.array([0.123], requires_grad=True)
    grads_def = circuit_gradient_def(params)

    assert np.allclose(grads_lig, grads_def)
Example #4
0
# will determine the name given to the saved files that are produced during the calculations:

name = 'h2'

##############################################################################
# The charge, multiplicity, and basis set can also be specified as keyword arguments. Finally,
# the number of active electrons and active orbitals may be indicated, as well as the
# fermionic-to-qubit mapping, which can be either Jordan-Wigner (``jordan_wigner``) or Bravyi-Kitaev
# (``bravyi_kitaev``). The outputs of the function are the qubit Hamiltonian of the molecule and the
# number of qubits needed to represent it:

h, qubits = qchem.molecular_hamiltonian(
    name,
    geometry,
    charge=charge,
    mult=multiplicity,
    basis=basis_set,
    active_electrons=2,
    active_orbitals=2,
    mapping='jordan_wigner'
)

print('Number of qubits = ', qubits)
print('Hamiltonian is ', h)

##############################################################################
# That's it! From here on, we can use PennyLane as usual, employing its entire stack of
# algorithms and optimizers.
#
# Implementing the VQE algorithm
# ------------------------------
#
class TestSparseExpvalQChem:
    """Tests for the expval function with qchem workflow"""

    symbols = ["Li", "H"]
    geometry = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 2.969280527])

    H, qubits = qchem.molecular_hamiltonian(
        symbols,
        geometry,
    )
    H_sparse = qml.utils.sparse_hamiltonian(H)

    active_electrons = 1

    hf_state = qchem.hf_state(active_electrons, qubits)

    singles, doubles = qchem.excitations(active_electrons, qubits)
    excitations = singles + doubles

    @pytest.fixture(params=[np.complex64, np.complex128])
    def dev(self, request):
        return qml.device("lightning.qubit", wires=12, c_dtype=request.param)

    @pytest.mark.parametrize(
        "qubits, wires, H_sparse, hf_state, excitations",
        [
            [qubits,
             np.arange(qubits), H_sparse, hf_state, excitations],
            [
                qubits,
                np.random.permutation(np.arange(qubits)),
                H_sparse,
                hf_state,
                excitations,
            ],
        ],
    )
    def test_sparse_Pauli_words(self, qubits, wires, H_sparse, hf_state,
                                excitations, tol, dev):
        """Test expval of some simple sparse Hamiltonian"""
        @qml.qnode(dev, diff_method="parameter-shift")
        def circuit():
            qml.BasisState(hf_state, wires=range(qubits))

            for i, excitation in enumerate(excitations):
                if len(excitation) == 4:
                    qml.DoubleExcitation(1, wires=excitation)
                elif len(excitation) == 2:
                    qml.SingleExcitation(1, wires=excitation)

            return qml.expval(qml.SparseHamiltonian(H_sparse, wires=wires))

        dev_default = qml.device("default.qubit", wires=qubits)

        @qml.qnode(dev_default, diff_method="parameter-shift")
        def circuit_default():
            qml.BasisState(hf_state, wires=range(qubits))

            for i, excitation in enumerate(excitations):
                if len(excitation) == 4:
                    qml.DoubleExcitation(1, wires=excitation)
                elif len(excitation) == 2:
                    qml.SingleExcitation(1, wires=excitation)

            return qml.expval(qml.SparseHamiltonian(H_sparse, wires=wires))

        assert np.allclose(circuit(), circuit_default(), atol=tol, rtol=0)
Example #6
0
    0.9: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_0.90.xyz",
    1.1: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_1.10.xyz",
    1.3: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_1.30.xyz",
    1.5: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_1.50.xyz",
    1.7: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_1.70.xyz",
    1.9: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_1.90.xyz",
    2.1: "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/vqe_parallel/h2_2.10.xyz",
}

##############################################################################
# The next step is to create the qubit Hamiltonians for each value of the inter-atomic distance.

hamiltonians = []

for separation, file in data.items():
    h = qchem.molecular_hamiltonian(name=str(separation), geo_file=file)[0]
    hamiltonians.append(h)

##############################################################################
# Each Hamiltonian can be written as a linear combination of fifteen tensor products of Pauli
# matrices. Let's take a look more closely at one of the Hamiltonians:

h = hamiltonians[0]

print("Number of terms: {}\n".format(len(h.ops)))
for op in h.ops:
    print("Measurement {} on wires {}".format(op.name, op.wires))

##############################################################################
# Defining the energy function
# ----------------------------
Example #7
0
    "Electronic Hamiltonian of the water molecule represented in the Pauli basis"
)
print(qubit_hamiltonian)

##############################################################################
# Finally, the :func:`~.pennylane_qchem.qchem.molecular_hamiltonian`
# function is used to automate the construction of the electronic Hamiltonian using
# the functions described above.
#
# An example usage is shown below:

H, qubits = qchem.molecular_hamiltonian(name,
                                        'h2o.xyz',
                                        charge=charge,
                                        mult=multiplicity,
                                        basis=basis_set,
                                        package='pyscf',
                                        active_electrons=4,
                                        active_orbitals=4,
                                        mapping='jordan_wigner')

print("Number of qubits required to perform quantum simulations: {:}".format(
    qubits))
print(
    "Electronic Hamiltonian of the water molecule represented in the Pauli basis"
)
print(H)

##############################################################################
# You have completed the tutorial! Now, select your favorite molecule and build its electronic
# Hamiltonian.
##############################################################################
# Finally, the :func:`~.pennylane_qchem.qchem.molecular_hamiltonian`
# function is used to automate the construction of the electronic Hamiltonian using
# the functions described above. It takes as input the atomic symbols and nuclear
# coordinates, which can be read directly from the geometry file.
#
# An example usage is shown below:

symbols, coordinates = qchem.read_structure('h2o.xyz')

H, qubits = qchem.molecular_hamiltonian(symbols,
                                        coordinates,
                                        charge=charge,
                                        mult=multiplicity,
                                        basis=basis_set,
                                        package='pyscf',
                                        active_electrons=4,
                                        active_orbitals=4,
                                        mapping='jordan_wigner')

print("Number of qubits required to perform quantum simulations: {:}".format(
    qubits))
print(
    "Electronic Hamiltonian of the water molecule represented in the Pauli basis"
)
print(H)

##############################################################################
# You have completed the tutorial! Now, select your favorite molecule and build its electronic
# Hamiltonian.
Example #9
0
    1.9: "vqe_parallel/h2_1.90.xyz",
    2.1: "vqe_parallel/h2_2.10.xyz",
}

##############################################################################
# The next step is to create the qubit Hamiltonians for each value of the inter-atomic distance.
# We do this by first reading the molecular geometry from the external file using the
# :func:`~.pennylane_qchem.qchem.read_structure` function and passing the atomic symbols
# and coordinates to :func:`~.pennylane_qchem.qchem.molecular_hamiltonian`.


hamiltonians = []

for separation, file in data.items():
    symbols, coordinates = qchem.read_structure(file)
    h = qchem.molecular_hamiltonian(symbols, coordinates, name=str(separation))[0]
    hamiltonians.append(h)

##############################################################################
# Each Hamiltonian can be written as a linear combination of fifteen tensor products of Pauli
# matrices. Let's take a look more closely at one of the Hamiltonians:

h = hamiltonians[0]

print("Number of terms: {}\n".format(len(h.ops)))
for op in h.ops:
    print("Measurement {} on wires {}".format(op.name, op.wires))

##############################################################################
# Defining the energy function
# ----------------------------
Example #10
0
    "Electronic Hamiltonian of the water molecule represented in the Pauli basis"
)
print(qubit_hamiltonian)

##############################################################################
# Finally, the :func:`~.pennylane_qchem.qchem.molecular_hamiltonian`
# function is used to automate the construction of the electronic Hamiltonian using
# the functions described above.
#
# An example usage is shown below:

H, qubits = qchem.molecular_hamiltonian(
    name,
    '/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/alldata/h2o.xyz',
    charge=charge,
    mult=multiplicity,
    basis=basis_set,
    package='pyscf',
    active_electrons=4,
    active_orbitals=4,
    mapping='jordan_wigner')

print("Number of qubits required to perform quantum simulations: {:}".format(
    qubits))
print(
    "Electronic Hamiltonian of the water molecule represented in the Pauli basis"
)
print(H)

##############################################################################
# You have completed the tutorial! Now, select your favorite molecule and build its electronic
# Hamiltonian.
Example #11
0
geometry = "/workspace/my-examples-for-quantum-computing/pennylaneai/qml-demos/alldata/h2.xyz"

##############################################################################
# The geometry of the molecule can be given in any format recognized by Open Babel.
# Here, we used a locally saved file in
# `xyz format <https://en.wikipedia.org/wiki/XYZ_file_format>`_ specifying the
# three-dimensional coordinates and symbols of the atomic species.
#
# In this example, we use a minimal `basis set
# <https://en.wikipedia.org/wiki/Basis_set_(chemistry)>`_ to model the hydrogen molecule.
# In this approximation, the qubit Hamiltonian of the molecule in the Jordan-Wigner
# representation is built using the :func:`~.pennylane_qchem.qchem.molecular_hamiltonian`
# function.

H, qubits = qchem.molecular_hamiltonian(name,
                                        geometry,
                                        mapping="jordan_wigner")

print("Number of qubits = ", qubits)
print("Hamiltonian is ", H)

##############################################################################
# The :func:`~.pennylane_qchem.qchem.molecular_hamiltonian` function allows us to define
# an additional set of keyword arguments to provide the user with ample flexibility
# to generate the Hamiltonian of more complicated systems. For more details take a look
# at the tutorial :doc:`tutorial_quantum_chemistry`.

##############################################################################
# We also want to build the total spin operator :math:`\hat{S}^2`,
#
# .. math::
Example #12
0
# SPSA and the variational quantum eigensolver
# --------------------------------------------
#
# Now that we've explored the theoretical underpinnings of SPSA, let's use it
# to optimize a real chemical system, that of the hydrogen molecule :math:`H_2`.
# This molecule was studied previously in the `introductory variational quantum
# eigensolver (VQE) demo </demos/tutorial_vqe>`_, and so we will reuse some of
# that machinery below to set up the problem.
#

from pennylane import qchem

geometry = "h2.xyz"

symbols, coordinates = qchem.read_structure(geometry)
h2_ham, num_qubits = qchem.molecular_hamiltonian(symbols, coordinates)

# Variational ansatz for H_2 - see Intro VQE demo for more details
def circuit(params, wires):
    qml.BasisState(np.array([1, 1, 0, 0]), wires=wires)
    for i in wires:
        qml.Rot(*params[i], wires=i)
    qml.CNOT(wires=[2, 3])
    qml.CNOT(wires=[2, 0])
    qml.CNOT(wires=[3, 1])


##############################################################################
#
# The :math:`H_2` Hamiltonian uses 4 qubits, contains 15 terms, and has a ground
# state energy of :math:`-1.136189454088` Hartree.
Example #13
0
##############################################################################
# The geometry of the molecule can be given in any format recognized by Open Babel.
# Here, we used a locally saved file in
# `xyz format <https://en.wikipedia.org/wiki/XYZ_file_format>`_ specifying the
# three-dimensional coordinates and symbols of the atomic species.
#
# In this example, we use a minimal `basis set
# <https://en.wikipedia.org/wiki/Basis_set_(chemistry)>`_ to model the hydrogen molecule.
# In this approximation, the qubit Hamiltonian of the molecule in the Jordan-Wigner
# representation is built using the :func:`~.pennylane_qchem.qchem.molecular_hamiltonian`
# function.

symbols, coordinates = qchem.read_structure(geometry)

H, qubits = qchem.molecular_hamiltonian(symbols,
                                        coordinates,
                                        mapping="jordan_wigner")

print("Number of qubits = ", qubits)
print("Hamiltonian is ", H)

##############################################################################
# The :func:`~.pennylane_qchem.qchem.molecular_hamiltonian` function allows us to define
# an additional set of keyword arguments to provide the user with ample flexibility
# to generate the Hamiltonian of more complicated systems. For more details take a look
# at the tutorial :doc:`tutorial_quantum_chemistry`.

##############################################################################
# We also want to build the total spin operator :math:`\hat{S}^2`,
#
# .. math::