Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add from_openfermion function for fermionic operators #5808

Merged
merged 35 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f81b445
Added from_openfermion function for fermionic operators
ddhawan11 Jun 6, 2024
afe7a9b
Fixed CI
ddhawan11 Jun 6, 2024
ec65f76
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 6, 2024
b66af0e
Fixed CI
ddhawan11 Jun 7, 2024
c331df3
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 7, 2024
78858e7
Fixed CI
ddhawan11 Jun 7, 2024
2d39690
Fixed tests
ddhawan11 Jun 7, 2024
6c04431
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 7, 2024
b414c7a
Increased test coverage
ddhawan11 Jun 7, 2024
9b9d0ee
Update pennylane/qchem/convert_fermionic.py
ddhawan11 Jun 11, 2024
ab7b6d2
Update doc/releases/changelog-dev.md
ddhawan11 Jun 11, 2024
de58bb0
Update pennylane/qchem/convert_fermionic.py
ddhawan11 Jun 11, 2024
bfa94fc
changed the conversion method to scratch
ddhawan11 Jun 12, 2024
fb58374
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 12, 2024
a598a14
formatted through black
ddhawan11 Jun 12, 2024
3a5ba46
fixed ci
ddhawan11 Jun 12, 2024
44da8ab
Update doc/releases/changelog-dev.md
ddhawan11 Jun 13, 2024
54d2a57
Update doc/releases/changelog-dev.md
ddhawan11 Jun 13, 2024
419d7da
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
ca36b4d
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
7b99884
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
02abae6
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 13, 2024
d9e71ae
Addressed reviews
ddhawan11 Jun 13, 2024
7b86106
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
aad2bdc
Addressed reviews
ddhawan11 Jun 13, 2024
560e5be
Made the function available at high-level
ddhawan11 Jun 13, 2024
f7b224d
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
5f0e220
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
f7747b2
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 13, 2024
ae5941f
changed variable name
ddhawan11 Jun 13, 2024
8426727
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 13, 2024
869de4a
Merge branch 'master' into pennylane_openfermion_integration
ddhawan11 Jun 14, 2024
92d667a
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 14, 2024
0fd08ff
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 14, 2024
762e112
Update pennylane/qchem/convert_openfermion.py
ddhawan11 Jun 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,21 @@
* The `default.tensor` device is introduced to perform tensor network simulations of quantum circuits using the `mps` (Matrix Product State) method.
[(#5699)](https://github.com/PennyLaneAI/pennylane/pull/5699)

* A new `qml.noise` module which contains utility functions for building `NoiseModels`.
* Added `from_openfermion` to convert openfermion `FermionOperator` objects to PennyLane `FermiWord` or
`FermiSentence` objects.
[(#5808)](https://github.com/PennyLaneAI/pennylane/pull/5808)

```python
of_op = openfermion.FermionOperator('0^ 2')
pl_op = qml.from_openfermion(of_op)

```
```pycon
>>> print(pl_op)
a⁺(0) a(2)
```

* A new `qml.noise` module which contains utililty functions for building `NoiseModels`.
[(#5674)](https://github.com/PennyLaneAI/pennylane/pull/5674)
[(#5684)](https://github.com/PennyLaneAI/pennylane/pull/5684)

Expand Down
1 change: 1 addition & 0 deletions pennylane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
paulix_ops,
taper_operation,
import_operator,
from_openfermion,
)
from pennylane._device import Device, DeviceError
from pennylane._grad import grad, jacobian, vjp, jvp
Expand Down
1 change: 1 addition & 0 deletions pennylane/qchem/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .basis_data import load_basisset
from .basis_set import BasisFunction, atom_basis_data, mol_basis_data
from .convert import import_operator, import_state
from .convert_openfermion import from_openfermion
from .dipole import dipole_integrals, dipole_moment, fermionic_dipole
from .factorization import basis_rotation, factorize
from .givens_decomposition import givens_decomposition
Expand Down
67 changes: 67 additions & 0 deletions pennylane/qchem/convert_openfermion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2018-2024 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 for converting an openfermion fermionic operator to Pennylane
FermiWord or FermiSentence operators
ddhawan11 marked this conversation as resolved.
Show resolved Hide resolved
"""
# pylint: disable= import-outside-toplevel,no-member,unused-import
from pennylane.fermi import FermiSentence, FermiWord


def from_openfermion(of_op, tol=1e-16):
ddhawan11 marked this conversation as resolved.
Show resolved Hide resolved
ddhawan11 marked this conversation as resolved.
Show resolved Hide resolved
r"""Convert OpenFermion
`FermionOperator <https://quantumai.google/reference/python/openfermion/ops/FermionOperator>`__
objects to PennyLane :class:`~.fermi.FermiWord` or :class:`~.fermi.FermiSentence` objects.
ddhawan11 marked this conversation as resolved.
Show resolved Hide resolved

Args:
of_op (FermionOperator): OpenFermion fermionic operator
tol (float): Tolerance for discarding coefficients
ddhawan11 marked this conversation as resolved.
Show resolved Hide resolved

Returns:
Union[FermiWord, FermiSentence]: the fermionic operator object

**Example**

>>> from openfermion import FermionOperator
>>> of_op = 0.5 * FermionOperator('0^ 2') + FermionOperator('0 2^')
>>> pl_op = from_openfermion(of_op)
>>> print(pl_op)
0.5 * a(0) a⁺(2)
+ 1.0 * a⁺(0) a(2)
ddhawan11 marked this conversation as resolved.
Show resolved Hide resolved
"""
try:
import openfermion
except ImportError as Error:
raise ImportError(
"This feature requires openfermion. "
"It can be installed with: pip install openfermion"
) from Error

typemap = {0: "-", 1: "+"}

fermi_words = []
fermi_coeffs = []

for ops, val in of_op.terms.items():
fw_dict = {(i, op[0]): typemap[op[1]] for i, op in enumerate(ops)}
fermi_words.append(FermiWord(fw_dict))
fermi_coeffs.append(val)

if len(fermi_words) == 1 and fermi_coeffs[0] == 1.0:
return fermi_words[0]

pl_op = FermiSentence(dict(zip(fermi_words, fermi_coeffs)))
pl_op.simplify(tol=tol)

return pl_op
130 changes: 130 additions & 0 deletions tests/qchem/of_tests/test_convert_openfermion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# 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.
"""
Unit tests for functions needed for converting objects obtained from external libraries to a
PennyLane object.
"""
# pylint: disable=too-many-arguments,protected-access
import sys

import pytest

import pennylane as qml
from pennylane import fermi

openfermion = pytest.importorskip("openfermion")


# PennyLane operators were obtained from openfermion operators manually
@pytest.mark.parametrize(
("of_op", "pl_op"),
[
(
openfermion.FermionOperator("3^ 2", 0.5) + openfermion.FermionOperator("0 2^", 1.0),
fermi.FermiSentence(
{
fermi.FermiWord({(0, 3): "+", (1, 2): "-"}): 0.5,
fermi.FermiWord({(0, 0): "-", (1, 2): "+"}): 1.0,
}
),
),
(
openfermion.FermionOperator("1^ 2^ 0 3", 1.2)
+ openfermion.FermionOperator("3^ 2^ 1 0", 4.5),
fermi.FermiSentence(
{
fermi.FermiWord({(0, 1): "+", (1, 2): "+", (2, 0): "-", (3, 3): "-"}): 1.2,
fermi.FermiWord({(0, 3): "+", (1, 2): "+", (2, 1): "-", (3, 0): "-"}): 4.5,
}
),
),
(
openfermion.FermionOperator("2^ 2", 1.5),
fermi.FermiSentence({fermi.FermiWord({(0, 2): "+", (1, 2): "-"}): 1.5}),
),
(openfermion.FermionOperator("0^ 0"), fermi.FermiWord({(0, 0): "+", (1, 0): "-"})),
(
openfermion.FermionOperator("1^ 2", 1.5)
+ openfermion.FermionOperator("2^ 1", 1.5)
+ openfermion.FermionOperator("3^ 2", 0.8),
fermi.FermiSentence(
{
fermi.FermiWord({(0, 1): "+", (1, 2): "-"}): 1.5,
fermi.FermiWord({(0, 2): "+", (1, 1): "-"}): 1.5,
fermi.FermiWord({(0, 3): "+", (1, 2): "-"}): 0.8,
}
),
),
(
openfermion.FermionOperator("3^ 4 5^ 6"),
fermi.FermiWord({(0, 3): "+", (1, 4): "-", (2, 5): "+", (3, 6): "-"}),
),
],
)
def test_convert_from_openfermion(of_op, pl_op):
r"""Test that conversion from openfermion fermionic operator to pennylane
fermionic operator is correct"""

converted_op = qml.qchem.from_openfermion(of_op)
assert converted_op == pl_op


def test_convert_from_openfermion_type_fw():
r"""Test that FermiWord object is returned when there is one term in the
fermionic operator with coefficient equal to 1.0"""

of_op = openfermion.FermionOperator("2^ 3")
converted_op = qml.qchem.from_openfermion(of_op)

assert isinstance(converted_op, qml.fermi.FermiWord)


def test_convert_from_openfermion_type_fs():
r"""Test that FermiSentence object is returned when there are multiple
terms in the fermionic operator"""

of_op = openfermion.FermionOperator("2^ 3") + openfermion.FermionOperator("1^ 2")
converted_op = qml.qchem.from_openfermion(of_op)

assert isinstance(converted_op, qml.fermi.FermiSentence)


def test_convert_from_openfermion_tol():
r"""Test that terms with coefficients larger than tolerance are discarded"""

of_op = (
openfermion.FermionOperator("2^ 3", 2.0)
+ openfermion.FermionOperator("1^ 2", 3.0)
+ openfermion.FermionOperator("2^ 1", 0.5)
)
truncated_op = fermi.FermiSentence(
{
fermi.FermiWord({(0, 2): "+", (1, 3): "-"}): 2.0,
fermi.FermiWord({(0, 1): "+", (1, 2): "-"}): 3.0,
}
)

converted_op = qml.qchem.from_openfermion(of_op, tol=0.6)

assert converted_op == truncated_op


def test_fail_import_openfermion(monkeypatch):
"""Test if an ImportError is raised when openfermion is requested but not installed"""

with monkeypatch.context() as m:
m.setitem(sys.modules, "openfermion", None)

with pytest.raises(ImportError, match="This feature requires openfermion"):
qml.qchem.from_openfermion(openfermion.FermionOperator("0^ 1"))
Loading