diff --git a/pennylane/resources/__init__.py b/pennylane/resources/__init__.py index 1b9ab49655f..875b2b4053a 100644 --- a/pennylane/resources/__init__.py +++ b/pennylane/resources/__init__.py @@ -15,5 +15,5 @@ The resources module provides the functionality to estimate the cost of implementing advanced quantum algorithms. """ - from .factorization import factorize +from .second_quantization import norm diff --git a/pennylane/resources/second_quantization.py b/pennylane/resources/second_quantization.py new file mode 100644 index 00000000000..7675548e453 --- /dev/null +++ b/pennylane/resources/second_quantization.py @@ -0,0 +1,81 @@ +# Copyright 2018-2022 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +This module contains the functions needed for resource estimation with double factorization method. +""" + +from pennylane import numpy as np + + +def norm(one, two, eigvals): + r"""Return the 1-norm of a molecular Hamiltonian from the one- and two-electron integrals and + eigenvalues of the factorized two-electron integral tensor. + + The 1-norm of a double-factorized molecular Hamiltonian is computed as + [`arXiv:2007.14460 `_] + + .. math:: + + \lambda = ||T|| + \frac{1}{4} \sum_r ||L^{(r)}||^2, + + where the Schatten 1-norm for a given matrix :math:`T` is defined as + + .. math:: + + ||T|| = \sum_k |\text{eigvals}[T]_k|. + + The matrices :math:`L^{(r)}` are obtained from factorization of the two-electron integral + tensor :math:`V` such that + + .. math:: + + V_{ijkl} = \sum_r L_{ij}^{(r)} L_{kl}^{(r) T}. + + The matrix :math:`T` is constructed from the one- and two-electron integrals as + + .. math:: + + T = h_{ij} - \frac{1}{2} \sum_l V_{illj} + \sum_l V_{llij}. + + Note that the two-electron integral tensor must be arranged in chemist notation. + + Args: + one (array[array[float]]): one-electron integrals + two (array[array[float]]): two-electron integrals + eigvals (array[float]): eigenvalues of the matrices obtained from factorizing the + two-electron integral tensor + + Returns: + array[float]: 1-norm of the Hamiltonian + + **Example** + + >>> symbols = ['H', 'H', 'O'] + >>> geometry = np.array([[0.00000000, 0.00000000, 0.28377432], + >>> [0.00000000, 1.45278171, -1.00662237], + >>> [0.00000000, -1.45278171, -1.00662237]], requires_grad=False) + >>> mol = qml.qchem.Molecule(symbols, geometry, basis_name='sto-3g') + >>> core, one, two = qml.qchem.electron_integrals(mol)() + >>> two = np.swapaxes(two, 1, 3) # convert to the chemists notation + >>> _, eigvals, _ = factorize(two, 1e-5) + >>> print(norm(one, two, eigvals)) + 52.98762043980203 + """ + lambda_one = 0.25 * np.sum([np.sum(abs(v)) ** 2 for v in eigvals]) + + t_matrix = one - 0.5 * np.einsum("illj", two) + np.einsum("llij", two) + t_eigvals, _ = np.linalg.eigh(t_matrix) + lambda_two = np.sum(abs(t_eigvals)) + + return lambda_one + lambda_two diff --git a/tests/resources/test_second_quantization.py b/tests/resources/test_second_quantization.py new file mode 100644 index 00000000000..161aff607ca --- /dev/null +++ b/tests/resources/test_second_quantization.py @@ -0,0 +1,52 @@ +# Copyright 2018-2021 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Unit tests for functions needed for resource estimation with double factorization method. +""" +import pytest + +import pennylane as qml +from pennylane import numpy as np + + +@pytest.mark.parametrize( + ("one", "two", "eigvals", "lamb_ref"), + [ + ( + np.array([[-1.25330961e00, 4.01900735e-14], [4.01900735e-14, -4.75069041e-01]]), + # two-electron integral is arranged in chemist notation + np.array( + [ + [ + [[6.74755872e-01, -4.60742555e-14], [-4.60742555e-14, 6.63711349e-01]], + [[-4.61020111e-14, 1.81210478e-01], [1.81210478e-01, -4.26325641e-14]], + ], + [ + [[-4.60464999e-14, 1.81210478e-01], [1.81210478e-01, -4.25215418e-14]], + [[6.63711349e-01, -4.28546088e-14], [-4.24105195e-14, 6.97651447e-01]], + ], + ] + ), + np.tensor( + [[-0.10489852, 0.10672343], [-0.42568824, 0.42568824], [-0.82864211, -0.81447282]] + ), + 1.6570518796336895, # lambda value obtained from openfermion + ) + ], +) +def test_df_norm(one, two, eigvals, lamb_ref): + r"""Test that the norm function returns the correct 1-norm.""" + lamb = qml.resources.norm(one, two, eigvals) + + assert np.allclose(lamb, lamb_ref)