Skip to content

Commit

Permalink
add num-num interaction and hopgate and improve gates docs
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinsung committed Sep 21, 2023
1 parent 5f86507 commit 1a6bb86
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 46 deletions.
2 changes: 2 additions & 0 deletions python/ffsim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
from ffsim.gates import (
apply_diag_coulomb_evolution,
apply_givens_rotation,
apply_hop_gate,
apply_num_interaction,
apply_num_num_interaction,
apply_num_op_prod_interaction,
apply_num_op_sum_evolution,
apply_orbital_rotation,
Expand Down
2 changes: 2 additions & 0 deletions python/ffsim/gates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
from ffsim.gates.diag_coulomb import apply_diag_coulomb_evolution
from ffsim.gates.gates import (
apply_givens_rotation,
apply_hop_gate,
apply_num_interaction,
apply_num_num_interaction,
apply_num_op_prod_interaction,
apply_tunneling_interaction,
)
Expand Down
3 changes: 2 additions & 1 deletion python/ffsim/gates/diag_coulomb.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ def apply_diag_coulomb_evolution(
.. math::
\mathcal{U}
\exp(-i t \sum_{i, j, \sigma, \tau} Z_{ij} n_{i, \sigma} n_{j, \tau} / 2)
\exp\left(-i t \sum_{i, j, \sigma, \tau}
Z_{ij} n_{i, \sigma} n_{j, \tau} / 2\right)
\mathcal{U}^\dagger
where :math:`n_{i, \sigma}` denotes the number operator on orbital :math:`i`
Expand Down
151 changes: 145 additions & 6 deletions python/ffsim/gates/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,19 @@ def apply_givens_rotation(
.. math::
G(\theta) = \exp(\theta (a^\dagger_i a_j - a\dagger_j a_i))
\text{G}(\theta) = \exp\left(\theta (a^\dagger_i a_j - a^\dagger_j a_i)\right)
Under the Jordan-Wigner transform, this gate has the following matrix when applied
to neighboring qubits:
.. math::
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & \cos(\theta) & -\sin(\theta) & 0\\
0 & \sin(\theta) & \cos(\theta) & 0\\
0 & 0 & 0 & 1 \\
\end{pmatrix}
Args:
vec: The state vector to be transformed.
Expand Down Expand Up @@ -102,7 +114,19 @@ def apply_tunneling_interaction(
.. math::
T(\theta) = \exp(i \theta (a^\dagger_i a_j + a\dagger_j a_i))
\text{T}(\theta) = \exp\left(i \theta (a^\dagger_i a_j + a^\dagger_j a_i)\right)
Under the Jordan-Wigner transform, this gate has the following matrix when applied
to neighboring qubits:
.. math::
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & \cos(\theta) & i \sin(\theta) & 0\\
0 & i \sin(\theta) & \cos(\theta) & 0\\
0 & 0 & 0 & 1 \\
\end{pmatrix}
Args:
vec: The state vector to be transformed.
Expand Down Expand Up @@ -147,7 +171,7 @@ def apply_num_interaction(
.. math::
N(\theta) = \exp(i \theta a^\dagger_i a_i)
\text{N}(\theta) = \exp\left(i \theta a^\dagger_i a_i\right)
Args:
vec: The state vector to be transformed.
Expand Down Expand Up @@ -184,6 +208,62 @@ def apply_num_interaction(
return vec


def apply_num_num_interaction(
vec: np.ndarray,
theta: float,
target_orbs: tuple[int, int],
norb: int,
nelec: tuple[int, int],
*,
copy: bool = True,
):
r"""Apply a number-number interaction gate.
The number-number interaction gate is
.. math::
\text{NN}(\theta) = \exp\left(i \theta a^\dagger_i a_i a^\dagger_j a_j\right)
Args:
vec: The state vector to be transformed.
theta: The rotation angle.
target_orbs: The orbitals on which to apply the interaction.
norb: The number of spatial orbitals.
nelec: The number of alpha and beta electrons.
copy: Whether to copy the vector before operating on it.
- If ``copy=True`` then this function always returns a newly allocated
vector and the original vector is left untouched.
- If ``copy=False`` then this function may still return a newly allocated
vector, but the original vector may have its data overwritten.
It is also possible that the original vector is returned,
modified in-place.
"""
if len(set(target_orbs)) == 1:
raise ValueError(
f"The orbitals to interact must be distinct. Got {target_orbs}."
)
if copy:
vec = vec.copy()
vec = apply_num_op_prod_interaction(
vec,
theta,
target_orbs=(target_orbs, []),
norb=norb,
nelec=nelec,
copy=False,
)
vec = apply_num_op_prod_interaction(
vec,
theta,
target_orbs=([], target_orbs),
norb=norb,
nelec=nelec,
copy=False,
)
return vec


def apply_num_op_prod_interaction(
vec: np.ndarray,
theta: float,
Expand All @@ -199,13 +279,15 @@ def apply_num_op_prod_interaction(
.. math::
NP(\theta) = \exp(i \theta \prod a^\dagger_{i, \sigma} a_{i, \sigma})
\text{NP}(\theta) =
\exp\left(i \theta \prod a^\dagger_{i, \sigma} a_{i, \sigma}\right)
Args:
vec: The state vector to be transformed.
theta: The rotation angle.
target_orbs: The orbitals on which to apply the interaction. This should
be a tuple of (orbital, spin) pairs.
target_orbs: A pair of lists of integers giving the orbitals on which to apply
the interaction. The first list specifies the alpha orbitals and the second
list specifies the beta orbitals.
norb: The number of spatial orbitals.
nelec: The number of alpha and beta electrons.
copy: Whether to copy the vector before operating on it.
Expand All @@ -228,3 +310,60 @@ def apply_num_op_prod_interaction(
copy=False,
)
return vec


def apply_hop_gate(
vec: np.ndarray,
theta: float,
target_orbs: tuple[int, int],
norb: int,
nelec: tuple[int, int],
*,
copy: bool = True,
) -> np.ndarray:
r"""Apply a hop gate.
A "hop gate" is a Givens rotation gate followed by a number-number interaction
gate with angle pi:
.. math::
\text{Hop}(\theta) = \text{NN}(\pi) \text{G}(\theta)
= \exp\left(i \pi a^\dagger_i a_i a^\dagger_j a_j\right)
\exp\left(\theta (a^\dagger_i a_j - a^\dagger_j a_i)\right)
Under the Jordan-Wigner transform, this gate has the following matrix when applied
to neighboring qubits:
.. math::
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & \cos(\theta) & -\sin(\theta) & 0\\
0 & \sin(\theta) & \cos(\theta) & 0\\
0 & 0 & 0 & -1 \\
\end{pmatrix}
Args:
vec: The state vector to be transformed.
theta: The rotation angle.
target_orbs: The orbitals (i, j) to rotate.
norb: The number of spatial orbitals.
nelec: The number of alpha and beta electrons.
copy: Whether to copy the vector before operating on it.
- If ``copy=True`` then this function always returns a newly allocated
vector and the original vector is left untouched.
- If ``copy=False`` then this function may still return a newly allocated
vector, but the original vector may have its data overwritten.
It is also possible that the original vector is returned,
modified in-place.
"""
if copy:
vec = vec.copy()
vec = apply_givens_rotation(
vec, theta, target_orbs, norb=norb, nelec=nelec, copy=False
)
vec = apply_num_num_interaction(
vec, np.pi, target_orbs, norb=norb, nelec=nelec, copy=False
)
return vec
2 changes: 1 addition & 1 deletion python/ffsim/gates/num_op_sum.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def apply_num_op_sum_evolution(
.. math::
\mathcal{U}
\exp(-i t \sum_{i, \sigma} \lambda_i n_{i, \sigma})
\exp\left(-i t \sum_{i, \sigma} \lambda_i n_{i, \sigma}\right)
\mathcal{U}^\dagger
where :math:`n_{i, \sigma}` denotes the number operator on orbital :math:`i`
Expand Down
2 changes: 1 addition & 1 deletion python/ffsim/gates/orbital_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def apply_orbital_rotation(
.. math::
\exp(\sum_{ij} log(U)_{ij} a^\dagger{i} a_j)
\exp\left(\sum_{ij} \log(U)_{ij} a^\dagger_i a_j\right)
Args:
vec: The state vector to be transformed.
Expand Down
Loading

0 comments on commit 1a6bb86

Please sign in to comment.