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

Methods to commute terms in Fermi objects #6196

Merged
merged 87 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
631833b
first draft of commuting relations with tests
willjmax Aug 29, 2024
8c2ed0b
tests for exceptions in commute methods
willjmax Aug 29, 2024
e09336a
implemented source -> target commuting
willjmax Aug 30, 2024
0a66801
fixed the implementation
willjmax Aug 30, 2024
2282a60
linting
willjmax Aug 30, 2024
313c70c
cleanup
willjmax Aug 30, 2024
b22bcae
docstrings and other cleanup
willjmax Aug 30, 2024
51e3ea1
fixing import order
willjmax Aug 30, 2024
b2e44fa
Merge branch 'master' into fermi-commute
willjmax Sep 4, 2024
1973dc6
updating documentation
willjmax Sep 4, 2024
a11b91f
renaming variables in _commute_adjacent
willjmax Sep 4, 2024
5b0eb58
updated changelog
willjmax Sep 4, 2024
6951466
fixing import order
willjmax Sep 4, 2024
d18047d
Merge branch 'master' into fermi-commute
willjmax Sep 4, 2024
e467d24
isort fix
willjmax Sep 4, 2024
e289b60
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 4, 2024
4d424e8
Merge branch 'master' into fermi-commute
willjmax Sep 5, 2024
08423ac
Merge branch 'master' into fermi-commute
willjmax Sep 6, 2024
f907fef
remove blank line in changelog
willjmax Sep 6, 2024
e665c80
grammar in documentation
willjmax Sep 6, 2024
94f75f6
Merge branch 'master' into fermi-commute
willjmax Sep 6, 2024
f8d229b
changing return
willjmax Sep 6, 2024
45dca4c
added exception to docstring
willjmax Sep 6, 2024
9179c29
import order
willjmax Sep 6, 2024
418c937
renaming variables
willjmax Sep 6, 2024
b2395f4
Merge branch 'master' into fermi-commute
willjmax Sep 6, 2024
de74754
isort
willjmax Sep 6, 2024
6ea8de1
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 6, 2024
c47384e
rewrite left/middle/right logic
willjmax Sep 6, 2024
0c1d3e9
Merge branch 'master' into fermi-commute
willjmax Sep 6, 2024
47bc4fd
linting
willjmax Sep 6, 2024
b0d4395
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 6, 2024
347af28
linting
willjmax Sep 6, 2024
80187cf
punctuation
willjmax Sep 6, 2024
9a175dd
punctuation
willjmax Sep 6, 2024
8be0aa1
formatting
willjmax Sep 6, 2024
9174375
minor cleanup
willjmax Sep 6, 2024
28f1fba
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 6, 2024
2926e7b
simplifying commute_adjacent
willjmax Sep 6, 2024
4c60f92
linting
willjmax Sep 6, 2024
d44af2c
Merge branch 'master' into fermi-commute
willjmax Sep 9, 2024
6679c57
addressing review comments, updating changelog
willjmax Sep 10, 2024
3bdea11
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 10, 2024
4db85a3
Merge branch 'master' into fermi-commute
willjmax Sep 10, 2024
54f30ab
removing unused import
willjmax Sep 10, 2024
9dd85ae
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 10, 2024
82eb015
formatting
willjmax Sep 10, 2024
15d1b3a
Merge branch 'master' into fermi-commute
willjmax Sep 11, 2024
fea03e8
removing _commute_adjacent
willjmax Sep 11, 2024
5f5f5db
renaming commute
willjmax Sep 11, 2024
5bfa23f
updated docstring
willjmax Sep 11, 2024
e3794c6
Merge branch 'master' into fermi-commute
willjmax Sep 12, 2024
ef52fdf
Merge branch 'master' into fermi-commute
willjmax Sep 12, 2024
f5bb0fe
Merge branch 'master' into fermi-commute
willjmax Sep 12, 2024
24cef4a
Merge branch 'master' into fermi-commute
willjmax Sep 12, 2024
dd2f231
Merge branch 'master' into fermi-commute
willjmax Sep 13, 2024
8a9d771
grammar in docstring
willjmax Sep 13, 2024
32cb979
simplifying fermisentence construction
willjmax Sep 13, 2024
39f5647
code cleanup
willjmax Sep 13, 2024
6cadb44
Merge branch 'master' into fermi-commute
willjmax Sep 13, 2024
4580d9e
Cleaning up docstrings
willjmax Sep 13, 2024
c35f19c
updating documentation
willjmax Sep 13, 2024
b892af7
fixing latex in documentation
willjmax Sep 13, 2024
cf7481f
fixing latex
willjmax Sep 13, 2024
b1ecd77
indentation
willjmax Sep 13, 2024
d5fa636
updating docstring
willjmax Sep 13, 2024
58809e1
added commas
willjmax Sep 13, 2024
ddde204
Merge branch 'master' into fermi-commute
willjmax Sep 13, 2024
59d699b
fixing latex again
willjmax Sep 13, 2024
92372f6
latex in documentation
willjmax Sep 16, 2024
3cd4415
Merge branch 'master' into fermi-commute
willjmax Sep 16, 2024
1a63c26
Merge branch 'master' into fermi-commute
willjmax Sep 16, 2024
432ba76
changes to documentation
willjmax Sep 16, 2024
e9b8fbb
changes to documentation
willjmax Sep 16, 2024
b6086ac
Merge branch 'master' into fermi-commute
willjmax Sep 16, 2024
18d738b
edits to latex
willjmax Sep 17, 2024
7e35922
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 17, 2024
6f206e7
Merge branch 'master' into fermi-commute
willjmax Sep 17, 2024
aff6bc3
linting
willjmax Sep 17, 2024
118dffb
Merge branch 'fermi-commute' of github.com:willjmax/pennylane into fe…
willjmax Sep 17, 2024
1e1557d
Merge branch 'master' into fermi-commute
willjmax Sep 17, 2024
057f604
Merge branch 'master' into fermi-commute
willjmax Sep 17, 2024
6bdf667
adding commas
willjmax Sep 18, 2024
1aa1f56
Merge branch 'master' into fermi-commute
willjmax Sep 18, 2024
45842f2
Merge branch 'master' into fermi-commute
willjmax Sep 18, 2024
684b878
editing docs
willjmax Sep 18, 2024
5f83275
Merge branch 'master' into fermi-commute
willjmax Sep 18, 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
4 changes: 4 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
`from pennylane.capture.primitives import *`.
[(#6129)](https://github.com/PennyLaneAI/pennylane/pull/6129)

* `FermiWord` and `FermiSentence` classes now have methods to apply
anti-commutator relations.
[(#6196)](https://github.com/PennyLaneAI/pennylane/pull/6196)

* The `SampleMP.process_samples` method is updated to support using JAX tracers
for samples, allowing compatiblity with Catalyst workflows.
[(#6211)](https://github.com/PennyLaneAI/pennylane/pull/6211)
Expand Down
142 changes: 142 additions & 0 deletions pennylane/fermi/fermionic.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,117 @@ def to_mat(self, n_orbitals=None):

return mat

def commute(self, source, target):
willjmax marked this conversation as resolved.
Show resolved Hide resolved
r"""Apply anti-commuting relations until the operator in position source is in position target.
willjmax marked this conversation as resolved.
Show resolved Hide resolved

willjmax marked this conversation as resolved.
Show resolved Hide resolved
Args:
source (int): The position of the operator to be commuted.
willjmax marked this conversation as resolved.
Show resolved Hide resolved
willjmax marked this conversation as resolved.
Show resolved Hide resolved
target (int): The desired position of the operator occupying the source position.

Returns:
FermiSentence: The ``FermiSentence`` obtained after applying the anti-commutator relations.

Raises:
TypeError: if the source or target is not an integer
ValueError: if the source or target are outside the range [0, len(self) - 1]


willjmax marked this conversation as resolved.
Show resolved Hide resolved
**Example**

>>> w = FermiWord({(0, 0): '+', (1, 1): '-'})
willjmax marked this conversation as resolved.
Show resolved Hide resolved
>>> w.commute(0, 1)
-1 * a(1) a⁺(0)
willjmax marked this conversation as resolved.
Show resolved Hide resolved
"""

if not isinstance(source, int) or not isinstance(target, int):
raise TypeError("Positions must be integers")
willjmax marked this conversation as resolved.
Show resolved Hide resolved

if source < 0 or target < 0:
raise ValueError("Positions must be positive integers")
willjmax marked this conversation as resolved.
Show resolved Hide resolved

if source > len(self.sorted_dic) - 1 or target > len(self.sorted_dic) - 1:
raise ValueError("Positions out of range")
willjmax marked this conversation as resolved.
Show resolved Hide resolved

if source == target:
return FermiSentence({self: 1})

fw = self
obliviateandsurrender marked this conversation as resolved.
Show resolved Hide resolved
willjmax marked this conversation as resolved.
Show resolved Hide resolved
fs = FermiSentence({self: 1})
delta = 1 if source < target else -1

while source != target:
fs, fw = _commute_adjacent(fs, fw, source, source + delta)
willjmax marked this conversation as resolved.
Show resolved Hide resolved
source += delta
willjmax marked this conversation as resolved.
Show resolved Hide resolved

return fs


def _commute_adjacent(fs, fw, source, target):
willjmax marked this conversation as resolved.
Show resolved Hide resolved
"""Commutes two adjacent operators within a ``FermiSentence``.

Args:
fs (``FermiSentence``): The ``FermiSentence`` to be modified
willjmax marked this conversation as resolved.
Show resolved Hide resolved
fw (``FermiWord``): The ``FermiWord`` within ``fs`` that contains the operators
to be commuted.
source (int): The position of the operator to be commuted.
target (int): The desired position of the operator occupying the source position.
willjmax marked this conversation as resolved.
Show resolved Hide resolved

Returns:
FermiSentence: The ``FermiSentence`` obtained after applying the anti-commutator relations.
FermiWord: The ``FermiWord`` that was modified by the commutation.

Raises:
ValueError: if the source and target positions are not consecutive
"""
if source != target + 1 and target != source + 1:
raise ValueError("Positions must be consecutive integers")

indices = list(fw.sorted_dic.keys())
source_idx = indices[source]
target_idx = indices[target]

source_val = fw[source_idx]
target_val = fw[target_idx]

# commuting identical terms
if source_idx[1] == target_idx[1] and source_val == target_val:
return fs, fw

new_source_idx = (source, target_idx[1])
new_target_idx = (target, source_idx[1])

coeff = fs.pop(fw)
fw = dict(fw)
fw[new_source_idx] = target_val
fw[new_target_idx] = source_val

if source_idx[1] != target_idx[1]:
del fw[source_idx]
del fw[target_idx]

fw = FermiWord(fw)

if source_val == target_val or source_idx[1] != target_idx[1]:
return fs + (-1 * FermiSentence({fw: coeff})), fw

_min = min(source, target)
_max = max(source, target)

items = list(fw.sorted_dic.items())
left = {(i, key[1]): value for i, (key, value) in enumerate(items[:_min])}
middle = {(i, key[1]): value for i, (key, value) in enumerate(items[_min : _max + 1])}
right = {(i, key[1]): value for i, (key, value) in enumerate(items[_max + 1 :])}

lfw = FermiWord(left)
mfw = FermiWord(middle)
rfw = FermiWord(right)

terms = lfw * (1 - FermiSentence({mfw: 1})) * rfw

fs = fs + coeff * terms
willjmax marked this conversation as resolved.
Show resolved Hide resolved

return fs, fw


# pylint: disable=useless-super-delegation
class FermiSentence(dict):
Expand Down Expand Up @@ -523,6 +634,37 @@ def to_mat(self, n_orbitals=None):

return mat

def commute(self, fw, source, target):
willjmax marked this conversation as resolved.
Show resolved Hide resolved
r"""Apply anti-commuting relations until the operator in position source is in position target.

Args:
fw (FermiWord): The FermiWord within the FermiSentence that contains the operator to be commuted.
willjmax marked this conversation as resolved.
Show resolved Hide resolved
source (int): The position of the operator to be commuted.
willjmax marked this conversation as resolved.
Show resolved Hide resolved
target (int): The desired position of the operator occupying the source position.

Returns:
FermiSentence: The FermiSentence obtained after applying the anti-commutator relations.
willjmax marked this conversation as resolved.
Show resolved Hide resolved
willjmax marked this conversation as resolved.
Show resolved Hide resolved

Raises:
ValueError: if the provided ``FermiWord`` is not in the ``FermiSentence`` dictionary

**Example**

>>> w = FermiWord({(0, 0): '+', (1, 1): '-'})
>>> s = FermiSentence({w: 1})
willjmax marked this conversation as resolved.
Show resolved Hide resolved
>>> s.commute(w, 0, 1)
-1 * a(1) a⁺(0)
"""

if fw not in self.keys():
raise ValueError(f"The FermiWord {fw} does not appear in the FermiSentence")

fs = dict(self)
coeff = fs[fw]
del fs[fw]
willjmax marked this conversation as resolved.
Show resolved Hide resolved

return FermiSentence(fs) + coeff * fw.commute(source, target)


def from_string(fermi_string):
r"""Return a fermionic operator object from its string representation.
Expand Down
128 changes: 127 additions & 1 deletion tests/fermi/test_fermionic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@
# limitations under the License.
"""Unit Tests for the Fermionic representation classes."""
import pickle
import re
from copy import copy, deepcopy

import numpy as np
import pytest

import pennylane as qml
from pennylane import numpy as pnp
from pennylane.fermi.fermionic import FermiSentence, FermiWord, _to_string, from_string
from pennylane.fermi.fermionic import (
FermiSentence,
FermiWord,
_commute_adjacent,
_to_string,
from_string,
)

# pylint: disable=too-many-public-methods

Expand All @@ -32,6 +39,62 @@
fw6 = FermiWord({(0, 10): "+", (1, 30): "+", (2, 0): "-", (3, 400): "-"})
fw7 = FermiWord({(0, 10): "-", (1, 30): "+", (2, 0): "-", (3, 400): "+"})

fw8 = FermiWord({(0, 0): "-", (1, 1): "+"})
fw8c = FermiWord({(0, 1): "+", (1, 0): "-"})
fw8cs = FermiSentence({fw8c: -1})

fw9 = FermiWord({(0, 0): "-", (1, 1): "-"})
fw9c = FermiWord({(0, 1): "-", (1, 0): "-"})
fw9cs = FermiSentence({fw9c: -1})

fw10 = FermiWord({(0, 0): "+", (1, 1): "+"})
fw10c = FermiWord({(0, 1): "+", (1, 0): "+"})
fw10cs = FermiSentence({fw10c: -1})

fw11 = FermiWord({(0, 0): "-", (1, 0): "+"})
fw11c = FermiWord({(0, 0): "+", (1, 0): "-"})
fw11cs = 1 + FermiSentence({fw11c: -1})

fw12 = FermiWord({(0, 0): "+", (1, 0): "+"})
fw12c = FermiWord({(0, 0): "+", (1, 0): "+"})
fw12cs = FermiSentence({fw12c: 1})

fw13 = FermiWord({(0, 0): "-", (1, 0): "-"})
fw13c = FermiWord({(0, 0): "-", (1, 0): "-"})
fw13cs = FermiSentence({fw13c: 1})

fw14 = FermiWord({(0, 0): "+", (1, 0): "-"})
fw14c = FermiWord({(0, 0): "-", (1, 0): "+"})
fw14cs = 1 + FermiSentence({fw14c: -1})

fw15 = FermiWord({(0, 0): "-", (1, 1): "+", (2, 2): "+"})
fw15c = FermiWord({(0, 1): "+", (1, 0): "-", (2, 2): "+"})
fw15cs = FermiSentence({fw15c: -1})

fw16 = FermiWord({(0, 0): "-", (1, 1): "+", (2, 2): "-"})
fw16c = FermiWord({(0, 0): "-", (1, 2): "-", (2, 1): "+"})
fw16cs = FermiSentence({fw16c: -1})

fw17 = FermiWord({(0, 0): "-", (1, 0): "+", (2, 2): "-"})
fw17c1 = FermiWord({(0, 2): "-"})
fw17c2 = FermiWord({(0, 0): "+", (1, 0): "-", (2, 2): "-"})
fw17cs = fw17c1 - fw17c2

fw18 = FermiWord({(0, 0): "+", (1, 1): "+", (2, 2): "-", (3, 3): "-"})
fw18c = FermiWord({(0, 0): "+", (1, 3): "-", (2, 1): "+", (3, 2): "-"})
fw18cs = FermiSentence({fw18c: 1})

fw19 = FermiWord({(0, 0): "+", (1, 1): "+", (2, 2): "-", (3, 2): "+"})
fw19c1 = FermiWord({(0, 0): "+", (1, 1): "+"})
fw19c2 = FermiWord({(0, 2): "+", (1, 0): "+", (2, 1): "+", (3, 2): "-"})
fw19cs = FermiSentence({fw19c1: 1, fw19c2: -1})

fw20 = FermiWord({(0, 0): "-", (1, 0): "+", (2, 1): "-", (3, 0): "-", (4, 0): "+"})
fw20c1 = FermiWord({(0, 0): "-", (1, 0): "+", (2, 1): "-"})
fw20c2 = FermiWord({(0, 0): "+", (1, 1): "-", (2, 0): "-"})
fw20c3 = FermiWord({(0, 0): "+", (1, 0): "-", (2, 0): "+", (3, 1): "-", (4, 0): "-"})
fw20cs = fw20c1 + fw20c2 - fw20c3


class TestFermiWord:
def test_missing(self):
Expand Down Expand Up @@ -141,6 +204,42 @@ def test_to_mat_error(self):
with pytest.raises(ValueError, match="n_orbitals cannot be smaller than 2"):
fw1.to_mat(n_orbitals=1)

tup_fw_commute = (
(fw8, 0, 1, fw8cs),
(fw9, 0, 1, fw9cs),
(fw10, 0, 1, fw10cs),
(fw11, 0, 1, fw11cs),
(fw12, 0, 1, fw12cs),
(fw13, 0, 1, fw13cs),
(fw14, 0, 1, fw14cs),
(fw15, 0, 1, fw15cs),
(fw16, 1, 2, fw16cs),
(fw17, 0, 1, fw17cs),
(fw8, 0, 0, FermiSentence({fw8: 1})),
(fw8, 1, 0, fw8cs),
(fw11, 1, 0, fw11cs),
(fw18, 3, 1, fw18cs),
(fw19, 3, 0, fw19cs),
(fw20, 4, 0, fw20cs),
)

@pytest.mark.parametrize("fw, i, j, fs", tup_fw_commute)
def test_commute(self, fw, i, j, fs):
assert fw.commute(i, j) == fs

def test_commute_errors(self):
with pytest.raises(TypeError, match="Positions must be integers"):
fw8.commute(0.5, 1)

with pytest.raises(ValueError, match="Positions must be positive integers"):
fw8.commute(-1, 0)

with pytest.raises(ValueError, match="Positions must be consecutive integers"):
_commute_adjacent(FermiSentence({fw17: 1}), fw17, 0, 2)

with pytest.raises(ValueError, match="Positions out of range"):
fw8.commute(1, 2)


class TestFermiWordArithmetic:
WORDS_MUL = (
Expand Down Expand Up @@ -528,6 +627,15 @@ def test_array_must_not_exceed_length_1(self, method_name):
}
)

fs8 = fw8 + fw9
fs8c = fw8 + fw9cs

fs9 = 1.3 * fw8 + (1.4 + 3.8j) * fw9
fs9c = 1.3 * fw8 + (1.4 + 3.8j) * fw9cs

fs10 = -1.3 * fw11 + 2.3 * fw9
fs10c = -1.3 * fw11cs + 2.3 * fw9


class TestFermiSentence:
def test_missing(self):
Expand Down Expand Up @@ -643,6 +751,24 @@ def test_to_mat_error(self):
with pytest.raises(ValueError, match="n_orbitals cannot be smaller than 3"):
fs7.to_mat(n_orbitals=2)

tup_fs_commute = (
(fs8, fw9, 0, 1, fs8c),
(fs9, fw9, 0, 1, fs9c),
(fs10, fw11, 0, 1, fs10c),
)

# pylint: disable=too-many-arguments
@pytest.mark.parametrize("fs, fw, i, j, fsc", tup_fs_commute)
def test_commute(self, fs, fw, i, j, fsc):
assert fs.commute(fw, i, j) == fsc

def test_commute_errors(self):
with pytest.raises(
ValueError,
match=re.escape(f"The FermiWord {fw11} does not appear in the FermiSentence"),
):
fs8.commute(fw11, 0, 1)


class TestFermiSentenceArithmetic:
tup_fs_mult = ( # computed by hand
Expand Down
Loading