Repository: qiskit-community/ffsim (python)

Issue:
Add keys, values, and items methods to FermionOperator
FermionOperator acts as a dictionary mapping keys to values. It should have `keys`, `values`, and `items` methods.

Pull request description:
Add Fermion operator mapping methods
Fixes #90 

Patch:
diff --git a/python/ffsim/operators/__init__.py b/python/ffsim/operators/__init__.py
index a58c7171..5fbd3ed3 100644
--- a/python/ffsim/operators/__init__.py
+++ b/python/ffsim/operators/__init__.py
@@ -10,7 +10,6 @@
 
 """Operators."""
 
-from ffsim._lib import FermionOperator
 from ffsim.operators.common_operators import number_operator
 from ffsim.operators.fermion_action import (
     FermionAction,
@@ -21,6 +20,7 @@ from ffsim.operators.fermion_action import (
     des_a,
     des_b,
 )
+from ffsim.operators.fermion_operator import FermionOperator
 
 __all__ = [
     "FermionAction",
diff --git a/python/ffsim/operators/fermion_operator.py b/python/ffsim/operators/fermion_operator.py
new file mode 100644
index 00000000..8ca33b0f
--- /dev/null
+++ b/python/ffsim/operators/fermion_operator.py
@@ -0,0 +1,32 @@
+# (C) Copyright IBM 2024.
+#
+# This code is licensed under the Apache License, Version 2.0. You may
+# obtain a copy of this license in the LICENSE.txt file in the root directory
+# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
+#
+# Any modifications or derivative works of this code must retain this
+# copyright notice, and modified files need to carry a notice indicating
+# that they have been altered from the originals.
+
+"""The FermionOperator class."""
+
+from collections.abc import ItemsView, KeysView, ValuesView
+
+from ffsim._lib import FermionOperator
+
+
+def keys(self):
+    return KeysView(self)
+
+
+def values(self):
+    return ValuesView(self)
+
+
+def items(self):
+    return ItemsView(self)
+
+
+FermionOperator.keys = keys  # type: ignore[method-assign]
+FermionOperator.values = values  # type: ignore[method-assign]
+FermionOperator.items = items  # type: ignore[method-assign]


Test patch:
diff --git a/tests/python/operators/fermion_operator_test.py b/tests/python/operators/fermion_operator_test.py
index afd6448f..46b8c574 100644
--- a/tests/python/operators/fermion_operator_test.py
+++ b/tests/python/operators/fermion_operator_test.py
@@ -614,3 +614,32 @@ def test_copy():
 
     copy *= 2
     assert copy != op
+
+
+def test_mapping_methods():
+    op = FermionOperator(
+        {
+            (ffsim.cre_a(1), ffsim.des_a(2)): 1,
+            (ffsim.cre_a(2), ffsim.des_a(1)): 0.5,
+            (ffsim.cre_b(1), ffsim.des_b(2)): -0.5j,
+            (ffsim.cre_b(2), ffsim.des_b(1)): 1 - 0.5j,
+        }
+    )
+    assert op.keys() == {
+        (ffsim.cre_a(1), ffsim.des_a(2)),
+        (ffsim.cre_a(2), ffsim.des_a(1)),
+        (ffsim.cre_b(1), ffsim.des_b(2)),
+        (ffsim.cre_b(2), ffsim.des_b(1)),
+    }
+    assert set(op.values()) == {
+        1,
+        0.5,
+        -0.5j,
+        1 - 0.5j,
+    }
+    assert op.items() == {
+        ((ffsim.cre_a(1), ffsim.des_a(2)), 1),
+        ((ffsim.cre_a(2), ffsim.des_a(1)), 0.5),
+        ((ffsim.cre_b(1), ffsim.des_b(2)), -0.5j),
+        ((ffsim.cre_b(2), ffsim.des_b(1)), 1 - 0.5j),
+    }