- A Web browser and a Google Account

The diagram below shows the energy of the molecule
as the distance between the two **H** atoms
changes. I got that diagram from **this page**.

Normally the molecule sits at its equilibrium distance, where the energy is at its minimum.

Squeezing the atoms together causes them to repel one another, like compressing a spring.

Pulling the atoms apart requires inputting energy,
like sending a rocket out of the Earth's gravity.
When the distance becomes large, the atoms break
apart, becoming separate **H** atoms.

The goal of this project is to model that energy curve, which determines how much energy is consumed or released in various chemical reactions.

If you see a blue "Sign In" button at the top right, click it and log into a Google account.https://colab.research.google.com/

From the menu, click **File**, "**New notebook**".

**pennylane**for quantum computing**openfermionpyscf**to make quantum algorithms to model electron states**qchem**for quantum chemistry**numpy**to perform math on arrays**pyplot**to draw graphs

As shown below, the commands run without errors, so the versions are OK.

!pip install pennylane !pip install openfermionpyscf import pennylane as qml from pennylane import qchem from pennylane import numpy as np import matplotlib.pyplot as plt

We begin with both **H** atoms completely in their
lowest-energy state, which is denoted as:

Execute the code below to prepare the qubits we need.|1100>

As shown below, the qubits are initialized.

# Hartree-Fock state hf = qml.qchem.hf_state(electrons=2, orbitals=4) print(hf)

As shown below, the code runs without errors, and produces no output.

# atomic symbols defining the molecule symbols = ['H', 'H'] # list to store energies energies = [] # set up a loop to change bond length r_range = np.arange(0.5, 5.0, 0.25) # keeps track of points in the potential energy surface pes_point = 0

As shown below, a diagram of the quantum circuit appears. The four inputs enter from the left, and pass through the gates, including some entanglements.

def circuit(parameters): # Prepare the HF state: |1100> qml.BasisState(hf, wires=range(qubits)) qml.DoubleExcitation(parameters[0], wires=[0, 1, 2, 3]) qml.SingleExcitation(parameters[1], wires=[0, 2]) qml.SingleExcitation(parameters[2], wires=[1, 3]) return qml.expval(H) # we are interested in minimizing this expectation value # Change only the z coordinate of one atom coordinates = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]]) # Construct the Molecule object molecule = qchem.Molecule(symbols, coordinates) # Obtain the qubit Hamiltonian H, qubits = qchem.molecular_hamiltonian(molecule, method='openfermion') # initialize the gate parameters params = np.zeros(3, requires_grad=True) drawer = qml.draw(circuit) print(drawer(params))

As shown below, code executes without errors, and produces no output.

# Set a fixed seed for reproducibility np.random.seed(42) def find_energy(r): global pes_point, params_old # Change only the z coordinate of one atom coordinates = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, r]]) # Construct the Molecule object molecule = qchem.Molecule(symbols, coordinates) # Obtain the qubit Hamiltonian H, qubits = qchem.molecular_hamiltonian(molecule, method='openfermion') # define the device, optimizer and circuit dev = qml.device("default.qubit", wires=qubits) opt = qml.GradientDescentOptimizer(stepsize=0.4) @qml.qnode(dev, interface='autograd') def circuit(parameters): # Prepare the HF state: |1100> qml.BasisState(hf, wires=range(qubits)) qml.DoubleExcitation(parameters[0], wires=[0, 1, 2, 3]) qml.SingleExcitation(parameters[1], wires=[0, 2]) qml.SingleExcitation(parameters[2], wires=[1, 3]) return qml.expval(H) # we are interested in minimizing this expectation value # initialize the gate parameters params = np.zeros(3, requires_grad=True) # initialize with converged parameters from previous point if pes_point > 0: params = params_old prev_energy = 0.0 for n in range(50): # perform optimization step params, energy = opt.step_and_cost(circuit, params) if np.abs(energy - prev_energy) < 1e-6: break prev_energy = energy # store the converged parameters params_old = params pes_point = pes_point + 1 return energy

energies = [] for r in r_range: energies.append(find_energy(r)) fig, ax = plt.subplots() ax.plot(r_range, energies) ax.set( xlabel="Bond length (Bohr)", ylabel="Total energy (Hartree)", title="Potential energy surface for H$_2$ dissociation", ) ax.grid() plt.show() # equilibrium energy e_eq = min(energies) # energy when atoms are far apart e_dis = energies[-1] # Bond dissociation energy bond_energy = e_dis - e_eq # Equilibrium bond length idx = energies.index(e_eq) bond_length = r_range[idx] print() print(f"The equilibrium bond length is {bond_length:.1f} Bohrs") print(f"The bond dissociation energy is {bond_energy:.3f} Hartrees")

## ML 170.1: Dissociation Energy (10 pts)

The flag is covered by a green rectangle in the image below.

The animation below shows the process, fromH+_{2}H→H+H_{2}

As shown below, the three qubits are initialized.

symbols = ["H", "H", "H"] multiplicity = 2 energies = [] pes_point = 0 # get all the singles and doubles excitations, and Hartree-Fock state electrons = 3 orbitals = 6 singles, doubles = qchem.excitations(electrons, orbitals) hf = qml.qchem.hf_state(electrons, orbitals) print(hf)

As shown below, a diagram of the quantum circuit appears. The six inputs enter from the left, and pass through AllSinglesDoubles template, which conveniently performs the necessary calculations for this problem.

from pennylane.templates import AllSinglesDoubles def circuit(parameters): AllSinglesDoubles(parameters, range(qubits), hf, singles, doubles) return qml.expval(H) # we are interested in minimizing this expectation value coordinates = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, r], [0.0, 0.0, 4.0]]) # We now specify the multiplicity molecule = qchem.Molecule(symbols, coordinates, mult=multiplicity) H, qubits = qchem.molecular_hamiltonian(molecule, method='openfermion') # initialize the gate parameters params = np.zeros(len(singles) + len(doubles), requires_grad=True) drawer = qml.draw(circuit) print(drawer(params))

As shown below, code executes without errors, and produces no output.

# Set a fixed seed for reproducibility np.random.seed(42) def find_energy(r): global pes_point, params_old coordinates = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, r], [0.0, 0.0, 4.0]]) # We now specify the multiplicity molecule = qchem.Molecule(symbols, coordinates, mult=multiplicity) H, qubits = qchem.molecular_hamiltonian(molecule, method='openfermion') dev = qml.device("default.qubit", wires=qubits) opt = qml.GradientDescentOptimizer(stepsize=1.5) @qml.qnode(dev, interface='autograd') def circuit(parameters): AllSinglesDoubles(parameters, range(qubits), hf, singles, doubles) return qml.expval(H) # we are interested in minimizing this expectation value params = np.zeros(len(singles) + len(doubles), requires_grad=True) if pes_point > 0: params = params_old prev_energy = 0.0 for n in range(60): params, energy = opt.step_and_cost(circuit, params) if np.abs(energy - prev_energy) < 1e-6: break prev_energy = energy # store the converged parameters params_old = params pes_point = pes_point + 1 return energy

energies = [] r_range = np.arange(1.0, 3.0, 0.1) for r in r_range: energies.append(find_energy(r)) fig, ax = plt.subplots() ax.plot(r_range, energies) ax.set( xlabel="Bond length (Bohr)", ylabel="Total energy (Hartree)", title="Energy surface for Hydrogen exchange ", ) ax.grid() plt.show() # Energy of the reactants and products - two minima on the PES e_eq1 = min(energies) e_eq2 = min([x for x in energies if x != e_eq1]) idx1 = energies.index(e_eq1) idx2 = energies.index(e_eq2) # Transition state is the local maximum between reactant and products idx_min = min(idx1, idx2) idx_max = max(idx1, idx2) # Transition state energy energy_ts = max(energies[idx_min:idx_max]) # Activation energy activation_energy = energy_ts - e_eq1 print() print(f"The activation energy is {activation_energy:.3f} Hartrees")

## ML 170.2: Activation Energy (10 pts)

The flag is covered by a green rectangle in the image below.

Quantum computing simulation of the hydrogen molecular ground-state energies with limited resources

Modelling chemical reactions on a quantum computer

**
**
Posted 8-2-24