Skip to content

Commit

Permalink
Merge pull request #86 from qiboteam/refactor-ansatzes
Browse files Browse the repository at this point in the history
Refactor code for some ansatzes
  • Loading branch information
damarkian authored Apr 4, 2024
2 parents 2e60ecc + c4a5564 commit eb83547
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 345 deletions.
4 changes: 2 additions & 2 deletions doc/source/api-reference/ansatz.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
Ansatz
======

This section covers the API reference for various chemistry ansatzes.
This section covers the API reference for various chemistry circuit ansatzes.

Hardware-efficient
------------------

.. autofunction:: qibochem.ansatz.hardware_efficient.hea
.. autofunction:: qibochem.ansatz.hardware_efficient.he_circuit


Hartree-Fock
Expand Down
3 changes: 1 addition & 2 deletions doc/source/getting-started/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ Here is an example of building the UCCD ansatz with the H2 molecule to test your
from qibo.models import VQE

from qibochem.driver.molecule import Molecule
from qibochem.ansatz.hf_reference import hf_circuit
from qibochem.ansatz.ucc import ucc_circuit
from qibochem.ansatz import hf_circuit, ucc_circuit

# Define the H2 molecule and obtain its 1-/2- electron integrals with PySCF
h2 = Molecule([('H', (0.0, 0.0, 0.0)), ('H', (0.0, 0.0, 0.7))])
Expand Down
24 changes: 7 additions & 17 deletions doc/source/tutorials/ansatz.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@ For the H\ :sub:`2` case discussed in previous sections, a possible hardware eff

.. code-block:: python
from qibo import Circuit
from qibochem.ansatz import he_circuit
from qibochem.ansatz import hardware_efficient
nlayers = 1
nqubits = 4
nfermions = 2
nlayers = 1
circuit = Circuit(4)
hardware_efficient_ansatz = hardware_efficient.hea(nlayers, nqubits)
circuit.add(hardware_efficient_ansatz)
circuit = he_circuit(nqubits, nlayers)
print(circuit.draw())
.. code-block:: output
Expand All @@ -43,11 +38,10 @@ The following example demonstrates how the energy of the H2 molecule is affected
.. code-block:: python
import numpy as np
from qibo import Circuit
from qibochem.driver.molecule import Molecule
from qibochem.driver import Molecule
from qibochem.measurement.expectation import expectation
from qibochem.ansatz import hardware_efficient
from qibochem.ansatz import he_circuit
mol = Molecule([("H", (0.0, 0.0, 0.0)), ("H", (0.0, 0.0, 0.74804))])
mol.run_pyscf()
Expand All @@ -57,10 +51,7 @@ The following example demonstrates how the energy of the H2 molecule is affected
nlayers = 1
nqubits = mol.nso
ntheta = 2 * nqubits * nlayers
hea_ansatz = hardware_efficient.hea(nlayers, nqubits)
circuit = Circuit(nqubits)
circuit.add(hea_ansatz)
circuit = he_circuit(nqubits, nlayers)
print("Energy expectation values for thetas: ")
print("-----------------------------")
Expand Down Expand Up @@ -116,8 +107,7 @@ An example of how to build a UCC doubles circuit ansatz for the :math:`H_2` mole
.. code-block:: python
from qibochem.driver.molecule import Molecule
from qibochem.ansatz.hf_reference import hf_circuit
from qibochem.ansatz.ucc import ucc_circuit
from qibochem.ansatz import hf_circuit, ucc_circuit
mol = Molecule([("H", (0.0, 0.0, 0.0)), ("H", (0.0, 0.0, 0.74804))])
mol.run_pyscf()
Expand Down
20 changes: 6 additions & 14 deletions examples/br_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@
"""

import numpy as np
from qibo import Circuit, gates, models
from qibo.optimizers import optimize
from scipy.optimize import minimize
from qibo.models import VQE

from qibochem.ansatz import basis_rotation
from qibochem.ansatz.hf_reference import hf_circuit
from qibochem.driver.molecule import Molecule
from qibochem.ansatz import basis_rotation, hf_circuit
from qibochem.driver import Molecule
from qibochem.measurement.expectation import expectation

# Define molecule and populate
mol = Molecule(xyz_file="h3p.xyz")
try:
mol.run_pyscf()
except ModuleNotFoundError:
mol.run_psi4()
mol.run_pyscf()

# Diagonalize H_core to use as the guess wave function

Expand Down Expand Up @@ -59,16 +53,14 @@ def basis_rotation_circuit(mol, parameters=0.0):
gate_layout = basis_rotation.basis_rotation_layout(nqubits)
gate_list, ordered_angles = basis_rotation.basis_rotation_gates(gate_layout, gate_angles, theta)

circuit = Circuit(nqubits)
for _i in range(mol.nelec):
circuit.add(gates.X(_i))
circuit = hf_circuit(nqubits, mol.nelec)
circuit.add(gate_list)

return circuit, gate_angles


br_circuit, qubit_parameters = basis_rotation_circuit(mol, parameters=0.1)
vqe = models.VQE(br_circuit, hamiltonian)
vqe = VQE(br_circuit, hamiltonian)
vqe_result = vqe.minimize(qubit_parameters)

print(f" HF energy: {mol.e_hf:.8f}")
Expand Down
48 changes: 25 additions & 23 deletions examples/ucc_example1.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@
from qibo.optimizers import optimize
from scipy.optimize import minimize

from qibochem.ansatz.hf_reference import hf_circuit
from qibochem.ansatz.ucc import ucc_circuit
from qibochem.ansatz import hf_circuit, ucc_circuit
from qibochem.driver.molecule import Molecule
from qibochem.measurement.expectation import expectation

# Define molecule and populate
mol = Molecule(xyz_file="lih.xyz")
try:
mol.run_pyscf()
except ModuleNotFoundError:
mol.run_psi4()
mol.run_pyscf()


# Apply embedding and boson encoding
mol.hf_embedding(active=[1, 2, 5])
hamiltonian = mol.hamiltonian(oei=mol.embed_oei, tei=mol.embed_tei, constant=mol.inactive_energy)
hamiltonian = mol.hamiltonian()

# Set parameters for the rest of the experiment
n_qubits = mol.n_active_orbs
Expand Down Expand Up @@ -56,11 +52,8 @@
n_unique_excitations = 5

# UCCSD: Circuit
all_coeffs = []
for _ex in excitations:
coeffs = []
circuit += ucc_circuit(n_qubits, _ex, coeffs=coeffs)
all_coeffs.append(coeffs)
circuit += ucc_circuit(n_qubits, _ex)

# Draw the circuit if interested
print(circuit.draw())
Expand All @@ -71,19 +64,28 @@ def electronic_energy(parameters):
r"""
Loss function for the UCCSD ansatz
"""
all_parameters = []
coeff_dict = {1: (-1.0, 1.0), 2: (-0.25, 0.25, 0.25, 0.25, -0.25, -0.25, -0.25, 0.25)}

# UCC parameters
# Expand the parameters to match the total UCC ansatz manually
_ucc = parameters[:n_unique_excitations]
# Unique UCC parameters
# Manually group the related excitations together
ucc_parameters = [_ucc[0], _ucc[1], _ucc[2], _ucc[2], _ucc[3], _ucc[3], _ucc[4], _ucc[4]]
# Need to iterate through each excitation this time
for _coeffs, _parameter in zip(all_coeffs, ucc_parameters):
ucc_parameters = [
parameters[0],
parameters[1],
parameters[2],
parameters[2],
parameters[3],
parameters[3],
parameters[4],
parameters[4],
]
all_parameters = []
# Iterate through each excitation, with the list of coefficients dependent on whether S/D excitation
for _ex, _parameter in zip(excitations, ucc_parameters):
coeffs = coeff_dict[len(_ex) // 2]
# Convert a single value to a array with dimension=n_param_gates
ucc_parameter = np.repeat(_parameter, len(_coeffs))
ucc_parameter = np.repeat(_parameter, len(coeffs))
# Multiply by coeffs
ucc_parameter *= _coeffs
ucc_parameter *= coeffs
all_parameters.append(ucc_parameter)

# Flatten all_parameters into a single list to set the circuit parameters
Expand All @@ -101,7 +103,7 @@ def electronic_energy(parameters):

best, params, extra = optimize(electronic_energy, params)

print("\nResults using Qibo optimize:")
print("\nResults using Qibo optimize: (With HF embedding)")
print(f"FCI energy: {fci_energy:.8f}")
print(f" HF energy: {mol.e_hf:.8f} (Classical)")
print(f"VQE energy: {best:.8f} (UCCSD ansatz)")
Expand All @@ -115,15 +117,15 @@ def electronic_energy(parameters):
result = minimize(electronic_energy, params)
best, params = result.fun, result.x

print("\nResults using scipy.optimize:")
print("\nResults using scipy.optimize: (With HF embedding)")
print(f"FCI energy: {fci_energy:.8f}")
print(f" HF energy: {mol.e_hf:.8f} (Classical)")
print(f"VQE energy: {best:.8f} (UCCSD ansatz)")
# print()
# print("Optimized parameters:", params)


full_ham = mol.hamiltonian("f")
full_ham = mol.hamiltonian("f", oei=mol.oei, tei=mol.tei, constant=0.0)
mol_fci_energy = mol.eigenvalues(full_ham)[0]

print(f"\nFCI energy: {mol_fci_energy:.8f} (Full Hamiltonian)")
91 changes: 0 additions & 91 deletions examples/ucc_example2.py

This file was deleted.

15 changes: 6 additions & 9 deletions src/qibochem/ansatz/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
from qibochem.ansatz.basis_rotation import (
basis_rotation_gates,
basis_rotation_layout,
givens_qr_decompose,
unitary,
)
from qibochem.ansatz.hardware_efficient import hea
from qibochem.ansatz.hf_reference import bk_matrix, bk_matrix_power2, hf_circuit
from qibochem.ansatz.basis_rotation import basis_rotation_gates
from qibochem.ansatz.hardware_efficient import he_circuit
from qibochem.ansatz.hf_reference import hf_circuit
from qibochem.ansatz.ucc import (
expi_pauli,
generate_excitations,
mp2_amplitude,
sort_excitations,
ucc_ansatz,
ucc_circuit,
)

# TODO: Probably can move some of the functions, e.g. generate_excitations/sort_excitations to a new 'util.py'
Loading

0 comments on commit eb83547

Please sign in to comment.