Unable to construct Hamiltonian

Dear Sir @Alain_Delgado_Gran. Thank you for sharing the information regarding significance of ‘3’ in coordinates and helping to convert into from Bohr to Angstrom as well. Also, thanks for sharing the information on how to get the molecular orbitals.

Sometime ago, I had also tried to get molecular orbital energies using OpenFermion. I have written some lines to get the frontier molecular orbital energies and their positions. I am just sharing the lines below.

“”"
import pennylane as qml
from pennylane import numpy as np
from openfermion import MolecularData

symb = [“Li”, “H”]
x = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 2.969280527], requires_grad=True)

lih = qml.qchem.meanfield(symb, x)
mol_LiH = MolecularData(filename=lih)

print("Number of orbitals: ", mol_LiH.n_orbitals)
print("Orbital energies: ", mol_LiH.orbital_energies)
print("Expansion coefficients: ", mol_LiH.canonical_orbitals)

molecule = mol_LiH
basis = ‘STO3G’

total_MOs = (molecule.canonical_orbitals.shape[0])
print(“No. of orbitals generated for basis set”,basis, molecule.canonical_orbitals.shape[0])

num_electrons = molecule.n_electrons
occupied_orbitals = round(num_electrons/2)
print(“No. of Occupied MOs for basis set”,basis, occupied_orbitals)
unoccupied_orbitals = total_MOs - occupied_orbitals
print(“No. of Unoccupied MOs for basis set”,basis, unoccupied_orbitals)

HOMO_position = round((num_electrons/2)-1)
LUMO_position = round((num_electrons/2)+0)

print(“The HOMO and LUMO positions are”,HOMO_position,LUMO_position)

HOMO_energy = molecule.orbital_energies[HOMO_position]
LUMO_energy = molecule.orbital_energies[LUMO_position]
H_L_Gap = LUMO_energy - HOMO_energy

print(“The HOMO and LUMO energies are”,round(HOMO_energy,5),round(LUMO_energy,5),“respectively in Hartrees”)
print(“The HOMO-LUMO gap is”, round(H_L_Gap,5),“in Hartrees”)
print(“The HOMO-LUMO gap is”, round(H_L_Gap*27.2114,3),“in eV”)

“”"

Also, regarding constructing the Hamiltonian, can you kindly help me understand the reason for ’ [0] ’ in the following line.

“def H(x):
return qml.qchem.molecular_hamiltonian(symbols, x, active_electrons=2, active_orbitals=3))[0]”

I am also working on obtaining ground state energies of a few small molecules. I will share the information with you after consolidating the results.

Thank you very much for your kind help.

Hi @raghavv,

Thank you for the update.

Regarding your question below:

Also, regarding constructing the Hamiltonian, can you kindly help me understand the reason for ’ [0] ’ in the following line.

Please, note that the molecular_hamiltonian function returns a tuple containing the built Hamiltonian and the number of qubits needed to represent it. Since you only need the Hamiltonian (for the example we have been discussing) the H(x) function returns the first element of the tuple.

Thank you!

1 Like

Dear Sir @Alain_Delgado_Gran, thank you for your kind response, I understand the importance of [0] now.

I am also learning the the chemical reaction tutorial of Pennylane (https://pennylane.ai/qml/demos/tutorial_chemical_reactions.html) and I am just curious to know if we can calculate the zero point vibrational energy in Pennylane while calculating dissociation energy of the molecule.

Thank you.

Hi @raghavv,

In principle you can calculate the zero point vibrational energy in PennyLane while calculating the dissociation energy of the molecule.

@Alain_Delgado_Gran is looking into what functionalities are available for this.

1 Like

Hi @raghavv,

Thank you for your question.

Yes, you can compute the zero-point energy correction from the vibrational frequencies of the molecule. In the harmonic approximation, they are given by the non-zero eigenvalues of the energy Hessian matrix defined as \frac{\partial^2E({\bf R})}{\partial R_i \partial R_j}. Here,E({\bf R}) is the total electronic energy of the ground or excited states of the molecule and {\bf R} denotes the optimized nuclear coordinates for a given electronic state (e.g. the ground state).

At present, we don’t have a tutorial showing how to compute the Hessian matrix elements \frac{\partial^2E({\bf R})}{\partial R_i \partial R_j} but I try to outline here how this can be done by combining different functionalities available in PennyLane. To that aim, I encourage you to check this paper by Mitarai et al. about computing analytical energy derivatives for the VQE algorithm. This contribution reports the expression to compute the second-order derivative of the energy with respect to the nuclear coordinates (See Eqs. (8) and (10) ). Evaluating this expression requires the following:

  • The equilibrium geometry of the molecule and the optimized circuit parameters to prepare its (electronic) ground-state.
  • Compute expectation values of the first- and second-order derivatives
    of the electronic Hamiltonian (defined for the optimized geometry) with respect to the nuclear coordinates. The Hamiltonian derivatives can be computed using finite-difference approximations or more accurate automatic differentiation tools available in PennyLane.
  • Compute the second-order derivative of the circuit (expectation value
    of the Hamiltonian) with respect to the gate parameters (Hessian of the circuit). See example here

Please, see the attached notebook with a working example to compute the second-order energy derivative for the trihydrogen cation.

Hope this helps!

Thank yousecond_derivative.ipynb|attachment (3.7 KB)

Hi @raghavv, here’s the file @Alain_Delgado_Gran had shared but in .py format. You should be able to paste it into a Jupyter notebook and run it.

second_derivative.py (2.2 KB)

1 Like

Thank you sir @Alain_Delgado_Gran for such a beautiful explanation with appropriate references. I will go thorugh them.

Thank you @CatalinaAlbornoz for sharing the code.

I tried to run the code, upon running the line " hessian = qml.jacobian(qml.grad(energy, argnum=0))(opt_param) ", it gave me the following error.

“”"

AttributeError Traceback (most recent call last)
/tmp/ipykernel_1076/1091415110.py in
1 # compute the Hessian of the quantum circuit
2 energy = expval(H(coord), opt_param)
----> 3 hessian = qml.jacobian(qml.grad(energy, argnum=0))(opt_param)

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/pennylane/_grad.py in _jacobian_function(*args, **kwargs)
179
180 if len(argnum) == 1:
–> 181 return _jacobian(func, argnum[0])(*args, **kwargs)
182
183 return np.stack([_jacobian(func, arg)(*args, **kwargs) for arg in argnum]).T

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/wrap_util.py in nary_f(*args, **kwargs)
18 else:
19 x = tuple(args[i] for i in argnum)
—> 20 return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
21 return nary_f
22 return nary_operator

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/differential_operators.py in jacobian(fun, x)
55 (out1, out2, …) then the Jacobian has shape (out1, out2, …, in1, in2, …).
56 “”"
—> 57 vjp, ans = _make_vjp(fun, x)
58 ans_vspace = vspace(ans)
59 jacobian_shape = ans_vspace.shape + vspace(x).shape

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/core.py in make_vjp(fun, x)
8 def make_vjp(fun, x):
9 start_node = VJPNode.new_root()
—> 10 end_value, end_node = trace(start_node, fun, x)
11 if end_node is None:
12 def vjp(g): return vspace(x).zeros()

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/tracer.py in trace(start_node, fun, x)
8 with trace_stack.new_trace() as t:
9 start_box = new_box(x, t, start_node)
—> 10 end_box = fun(start_box)
11 if isbox(end_box) and end_box._trace == start_box._trace:
12 return end_box._value, end_box._node

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/wrap_util.py in unary_f(x)
13 else:
14 subargs = subvals(args, zip(argnum, x))
—> 15 return fun(*subargs, **kwargs)
16 if isinstance(argnum, int):
17 x = args[argnum]

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/pennylane/_grad.py in call(self, *args, **kwargs)
99 “”“Evaluates the gradient function, and saves the function value
100 calculated during the forward pass in :attr:.forward.”""
–> 101 grad_value, ans = self._get_grad_fn(args)(*args, **kwargs)
102 self._forward = ans
103 return grad_value

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/wrap_util.py in nary_f(*args, **kwargs)
18 else:
19 x = tuple(args[i] for i in argnum)
—> 20 return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
21 return nary_f
22 return nary_operator

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/pennylane/_grad.py in _grad_with_forward(fun, x)
116 difference being that it returns both the gradient and the forward pass
117 value."""
–> 118 vjp, ans = _make_vjp(fun, x)
119
120 if not vspace(ans).size == 1:

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/core.py in make_vjp(fun, x)
8 def make_vjp(fun, x):
9 start_node = VJPNode.new_root()
—> 10 end_value, end_node = trace(start_node, fun, x)
11 if end_node is None:
12 def vjp(g): return vspace(x).zeros()

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/tracer.py in trace(start_node, fun, x)
8 with trace_stack.new_trace() as t:
9 start_box = new_box(x, t, start_node)
—> 10 end_box = fun(start_box)
11 if isbox(end_box) and end_box._trace == start_box._trace:
12 return end_box._value, end_box._node

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/autograd/wrap_util.py in unary_f(x)
13 else:
14 subargs = subvals(args, zip(argnum, x))
—> 15 return fun(*subargs, **kwargs)
16 if isinstance(argnum, int):
17 x = args[argnum]

/tmp/ipykernel_1076/3145879875.py in funct(params)
2 def expval(obs, params):
3 def funct(params):
----> 4 return circuit(params, obs, wires=range(qubits))
5 return funct

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/pennylane/qnode.py in call(self, *args, **kwargs)
604 if self.mutable or self.qtape is None:
605 # construct the tape
–> 606 self.construct(args, kwargs)
607
608 # Execute the tape.

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/pennylane/qnode.py in construct(self, args, kwargs)
523
524 with self.qtape:
–> 525 self.qfunc_output = self.func(*args, **kwargs)
526
527 if not isinstance(self.qfunc_output, Sequence):

/tmp/ipykernel_1076/3280061623.py in circuit(params, obs, wires)
6 qml.DoubleExcitation(params[0], wires=[0, 1, 2, 3])
7 qml.DoubleExcitation(params[1], wires=[0, 1, 4, 5])
----> 8 return qml.expval(obs)

~/psi4conda/envs/pennylane/lib/python3.9/site-packages/pennylane/measure.py in expval(op)
233 if not isinstance(op, (Observable, qml.Hamiltonian)):
234 raise qml.QuantumFunctionError(
–> 235 “{} is not an observable or Hamiltonian: cannot be used with expval”.format(op.name)
236 )
237

AttributeError: ‘tensor’ object has no attribute ‘name’

“”".
I am not sure why this error pops up. Can you help me troubleshoot this.

Thankyou.

Hi @raghavv, what version of Python and PennyLane are you using?

1 Like

Hi @CatalinaAlbornoz, Pennylane is 0.19.1 and Python is 3.8.12. Do you think I should upgrade.

Thank you.

Hi @raghavv,

Yes, installing the latest release of PennyLane should fix the problem.

Let us know.

Thank you.

1 Like

Thank you sir @Alain_Delgado_Gran. Will try upgrading and update the progress.
Thank you

Thank you sir @Alain_Delgado_Gran and @CatalinaAlbornoz. Will install latest Pennylane and try the Vibrational calculation and update.

Hi @raghavv.

Regarding this:

I carried out the calculation for LiH and it worked. I was unable to construct Hamiltonian for the bigger molecule such as PSPCz which I had mentioned in the first comment. That is why @sjahangiri had suggested me a work around. However, as you mentioned when the Hamiltonian is borrowed from Openfermion, I guess the nuclear gradient did not run.

You can run the geometry optimisation tutorial by building your Hamiltonian directly with OpenFermion. You just need to replace the H(x) function in the tutorial with the following, or something similar:

def H(x):
    geometry = [[s, tuple(x[3 * i : 3 * i + 3])] for i, s in enumerate(symbols)] # convert geometry to OF format
    molecule = openfermion.MolecularData(geometry, basis, multiplicity, charge)  # create molecule object
    hamiltonian = run_pyscf(molecule).get_molecular_hamiltonian()                # construct Hamiltonian
    hamiltonian = jordan_wigner(get_fermion_operator(hamiltonian))               # transform to qubit basis
    return qml.qchem.convert_observable(hamiltonian)                             # convert to PL Hamiltonian

However, please note that the black-box finite_diff function used in this tutorial will be deprecated soon. You can also have a look at the differentiable Hartree-Fock implementation which allows computing the gradients with qml.grad.

Finally, since your questions are important and other users might benefit from seeing them, I highly recommend creating new topics for different problems.

Hope this info is helpful.

1 Like

Hi Sir @sjahangiri. I am very sorry for the delayed response. Thank you for your detailed explanations.

Thank you sharing the code to optimize geometry as well and sharing the status of finite_diff.

Also, regarding the questions and answers, thank you for the remark. I thought it will be easier to go through from the same thread. But I will compile the questions and answers given by @sjahangiri, @CatalinaAlbornoz and @Alain_Delgado_Gran @maliasadi and create seperate threads and post them so that it will be visible to all of us.

I am working on optimizing the molecules. I will keep things updated.

Really thankful you for the immense support.

Thank you for the update @raghavv! Let us know how it goes when optimizing the molecules.

Dear @sjahangiri @Alain_Delgado_Gran @CatalinaAlbornoz. Thank you for your most valuable inputs. With an objective to optimize molecules using quantum computers, I have tried to integrate geom_opt and adaptive-circuit codes, with the help discussions carried out here. I am attaching the status of work here.

I will be grateful if you could kindly provide me a your esteemed feedback on it.

The attached file has extension .txt, kindly request you change it to .pdf for reading.

Please let me know if you need any further information.

Thank you

VariationalandGeometryOptimization.txt (2.1 MB)

Hi @raghavv, thanks for sharing this with us. Here are a few notes:

  • We usually write PennyLane with a capital P and a capital L (no spaces in the word)
  • You can add a citation for PennyLane (the software itself, not the demos) like this:
    Ville Bergholm, Josh Izaac, Maria Schuld, Christian Gogolin, M. Sohaib Alam, Shahnawaz Ahmed, Juan Miguel Arrazola, Carsten Blank, Alain Delgado, Soran Jahangiri, Keri McKiernan, Johannes Jakob Meyer, Zeyue Niu, Antal Száva, and Nathan Killoran. PennyLane: Automatic differentiation of hybrid quantum-classical computations. 2018. arXiv:1811.04968
  • You write “The quantum computer by Xanadu uses the paltofrom called Pennylane”. However PennyLane is a software that is not tied to any particular hardware so you might want to remove this phrase.

I can’t really comment on the contents but feel free to post this on our Slack and ask other members of the community to give you feedback.

Great initiative to write this!

1 Like