Skip to content
This repository has been archived by the owner on Sep 20, 2022. It is now read-only.

Commit

Permalink
Merge pull request #40 from zapatacomputing/dev
Browse files Browse the repository at this point in the history
Merge dev to master
  • Loading branch information
alexjuda authored Sep 29, 2021
2 parents 696e366 + f17b0db commit a01ec7d
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 3 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
"Operating System :: OS Independent",
],
setup_requires=["setuptools_scm~=6.0"],
install_requires=["z-quantum-core"],
install_requires=["z-quantum-core", "openfermion>=1.0.0"],
)
69 changes: 67 additions & 2 deletions src/python/zquantum/vqe/singlet_uccsd.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import numpy as np

from openfermion import uccsd_singlet_paramsize, uccsd_singlet_generator
from openfermion import (
uccsd_singlet_paramsize,
uccsd_singlet_generator,
FermionOperator,
)
from overrides import overrides
from typing import Optional
from typing import Optional, Tuple
import sympy

from zquantum.core.circuits import Circuit
Expand Down Expand Up @@ -102,6 +106,67 @@ def number_of_params(self) -> int:
n_electrons=self.number_of_electrons,
)

@staticmethod
def screen_out_operator_terms_below_threshold(
threshold: float, fermion_generator: FermionOperator, ignore_singles=False
) -> Tuple[np.ndarray, FermionOperator]:
"""Screen single and double excitation operators based on a guess
for the amplitudes
Args:
threshold (float): threshold to select excitations. Only those with
absolute amplitudes above the threshold are kept.
fermion_generator (openfermion.FermionOperator): Fermion Operator
containing the generators for the UCC ansatz
Returns:
amplitudes (np.array): screened amplitudes
new_fermion_generator (openfermion.FermionOperator): screened
Fermion Operator
"""

new_fermion_generator = FermionOperator()
amplitudes = []
for op in fermion_generator.terms:
if abs(fermion_generator.terms[op]) > threshold or (
len(op) == 2 and ignore_singles == True
):
new_fermion_generator += FermionOperator(
op, fermion_generator.terms[op]
)
amplitudes.append(fermion_generator.terms[op])
amplitudes = np.array(amplitudes)
return amplitudes, new_fermion_generator

def compute_uccsd_vector_from_fermion_generator(
self, raw_fermion_generator: FermionOperator, screening_threshold: float = 0.0
) -> np.ndarray:
_, screened_mp2_operator = self.screen_out_operator_terms_below_threshold(
screening_threshold, raw_fermion_generator
)

ansatz_operator = uccsd_singlet_generator(
np.arange(1.0, self.number_of_params + 1),
2 * self.number_of_spatial_orbitals,
self.number_of_electrons,
anti_hermitian=True,
)

params_vector = np.zeros(self.number_of_params)

for term, coeff in screened_mp2_operator.terms.items():
if term in ansatz_operator.terms.keys():
params_vector[int(ansatz_operator.terms[term]) - 1] = coeff

return params_vector

def generate_circuit_from_fermion_generator(
self, raw_fermion_generator: FermionOperator, screening_threshold: float = 0.0
) -> Circuit:
params_vector = self.compute_uccsd_vector_from_fermion_generator(
raw_fermion_generator, screening_threshold
)

return self.get_executable_circuit(params_vector)

@overrides
def _generate_circuit(self, params: Optional[np.ndarray] = None) -> Circuit:
"""
Expand Down
69 changes: 69 additions & 0 deletions tests/zquantum/vqe/singlet_uccsd_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import numpy as np
import pytest
from openfermion import FermionOperator
from zquantum.core.circuits import Circuit
from zquantum.core.interfaces.ansatz_test import AnsatzTests
from zquantum.vqe.singlet_uccsd import SingletUCCSDAnsatz

Expand Down Expand Up @@ -35,6 +38,38 @@ def ansatz(
transformation=transformation,
)

@pytest.fixture
def raw_ccsd_fop(self):
result_fop = FermionOperator()
result_fop += -0.0252893416 * FermionOperator("4^ 0 5^ 1")
result_fop += -0.0252893416 * FermionOperator("5^ 1 4^ 0")
result_fop += -0.0142638609 * FermionOperator("6^ 0 7^ 1")
result_fop += -0.0142638609 * FermionOperator("7^ 1 6^ 0")
result_fop += -0.00821798305 * FermionOperator("2^ 0 3^ 1")
result_fop += -0.00821798305 * FermionOperator("3^ 1 2^ 0")
result_fop += -0.00783761365 * FermionOperator("2^ 0 7^ 1")
result_fop += -0.00783761365 * FermionOperator("3^ 1 6^ 0")
result_fop += -0.00783761365 * FermionOperator("6^ 0 3^ 1")
result_fop += -0.00783761365 * FermionOperator("7^ 1 2^ 0")

return result_fop

@pytest.fixture
def expected_mp2_based_guess(self):
return np.array(
[
0.0,
0.0,
0.0,
-0.00821798,
-0.02528934,
-0.01426386,
0.0,
-0.00783761,
0.0,
]
)

def test_set_number_of_layers_invalidates_parametrized_circuit(self, ansatz):
# This test overwrites test from base class AnsatzTests.
pytest.xfail("Singlet UCCSD Ansatz can only have one layer")
Expand Down Expand Up @@ -165,3 +200,37 @@ def test_set_transformation(self, ansatz):

# Then
assert ansatz.transformation == new_transformation

@pytest.mark.parametrize(
"threshold,expected_new_size", [(0.0, 10), (1.0, 0), (0.025, 2)]
)
def test_screening_out_function(self, raw_ccsd_fop, threshold, expected_new_size):
_, new_fop = SingletUCCSDAnsatz.screen_out_operator_terms_below_threshold(
threshold, raw_ccsd_fop
)

assert len(new_fop.terms) == expected_new_size

def test_computing_uccsd_vector_from_fermion_generator(
self, raw_ccsd_fop, expected_mp2_based_guess
):
ansatz = SingletUCCSDAnsatz(4, 1)

np.testing.assert_array_almost_equal(
ansatz.compute_uccsd_vector_from_fermion_generator(raw_ccsd_fop),
expected_mp2_based_guess,
)

def test_generating_circuit_from_fermion_generator(
self, raw_ccsd_fop, expected_mp2_based_guess
):
ansatz = SingletUCCSDAnsatz(4, 1)

circuit = ansatz.generate_circuit_from_fermion_generator(raw_ccsd_fop)
assert isinstance(circuit, Circuit)

# Let's create a simple mock here to check params
ansatz.get_executable_circuit = lambda x: x

passed_params = ansatz.generate_circuit_from_fermion_generator(raw_ccsd_fop)
np.testing.assert_array_almost_equal(passed_params, expected_mp2_based_guess)

0 comments on commit a01ec7d

Please sign in to comment.