Skip to content

Commit

Permalink
Add Christiansen mapping for mapping christiansen bosons (#6623)
Browse files Browse the repository at this point in the history
**Context:**
Add christiansen_mapping function

**Description of the Change:**
Added function for mapping hardcore bosonic operators to qubit operators
using christiansen mapping

**Benefits:**

**Possible Drawbacks:**

**Related GitHub Issues:**


[sc-72640]

---------

Co-authored-by: Austin Huang <[email protected]>
Co-authored-by: Austin Huang <[email protected]>
Co-authored-by: soranjh <[email protected]>
  • Loading branch information
4 people authored Nov 27, 2024
1 parent 293403c commit b8d0b91
Show file tree
Hide file tree
Showing 6 changed files with 502 additions and 2 deletions.
2 changes: 1 addition & 1 deletion doc/code/qml_bose.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ Mapping to qubit operators

~binary_mapping
~unary_mapping

~christiansen_mapping

4 changes: 4 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
* Added a second class `DefaultMixedNewAPI` to the `qml.devices.qubit_mixed` module, which is to be the replacement of legacy `DefaultMixed` which for now to hold the implementations of `preprocess` and `execute` methods.
[(#6607)](https://github.com/PennyLaneAI/pennylane/pull/6507)

* Added `christiansen_mapping()` function to map `BoseWord` and `BoseSentence` to qubit operators, using christiansen mapping.
[(#6623)](https://github.com/PennyLaneAI/pennylane/pull/6623)

* Added `unary_mapping()` function to map `BoseWord` and `BoseSentence` to qubit operators, using unary mapping.
[(#6576)](https://github.com/PennyLaneAI/pennylane/pull/6576)

Expand Down Expand Up @@ -286,6 +289,7 @@ This release contains contributions from (in alphabetical order):
Shiwen An,
Astral Cai,
Yushao Chen,
Diksha Dhawan,
Pietropaolo Frisoni,
Austin Huang,
Korbinian Kottmann,
Expand Down
1 change: 1 addition & 0 deletions pennylane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
BoseWord,
binary_mapping,
unary_mapping,
christiansen_mapping,
)
from pennylane.qchem import (
taper,
Expand Down
2 changes: 1 addition & 1 deletion pennylane/bose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
"""A module containing utility functions and mappings for working with bosonic operators. """

from .bosonic import BoseSentence, BoseWord
from .bosonic_mapping import unary_mapping, binary_mapping
from .bosonic_mapping import binary_mapping, christiansen_mapping, unary_mapping
103 changes: 103 additions & 0 deletions pennylane/bose/bosonic_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,106 @@ def _(bose_operator: BoseSentence, n_states, tol=None):
qubit_operator.simplify(tol=1e-16)

return qubit_operator


def christiansen_mapping(
bose_operator: Union[BoseWord, BoseSentence],
ps: bool = False,
wire_map: dict = None,
tol: float = None,
):
r"""Convert a bosonic operator to a qubit operator using the Christiansen mapping.
This mapping assumes that the maximum number of allowed bosonic states is 2 and works only for
Christiansen bosons defined in `J. Chem. Phys. 120, 2140 (2004)
<https://pubs.aip.org/aip/jcp/article-abstract/120/5/2140/534128/A-second-quantization-formulation-of-multimode?redirectedFrom=fulltext>`_.
The bosonic creation and annihilation operators are mapped to the Pauli operators as
.. math::
b^{\dagger}_0 = \left (\frac{X_0 - iY_0}{2} \right ), \:\: \text{...,} \:\:
b^{\dagger}_n = \frac{X_n - iY_n}{2},
and
.. math::
b_0 = \left (\frac{X_0 + iY_0}{2} \right ), \:\: \text{...,} \:\:
b_n = \frac{X_n + iY_n}{2},
where :math:`X`, :math:`Y`, and :math:`Z` are the Pauli operators.
Args:
bose_operator(BoseWord, BoseSentence): the bosonic operator
ps (bool): Whether to return the result as a PauliSentence instead of an
operator. Defaults to False.
wire_map (dict): A dictionary defining how to map the states of
the Bose operator to qubit wires. If None, integers used to
label the bosonic states will be used as wire labels. Defaults to None.
tol (float): tolerance for discarding the imaginary part of the coefficients
Returns:
Union[PauliSentence, Operator]: A linear combination of qubit operators.
"""

qubit_operator = _christiansen_mapping_dispatch(bose_operator, tol)

wires = list(bose_operator.wires) or [0]
identity_wire = wires[0]
if not ps:
qubit_operator = qubit_operator.operation(wire_order=[identity_wire])

if wire_map:
return qubit_operator.map_wires(wire_map)

return qubit_operator


@singledispatch
def _christiansen_mapping_dispatch(bose_operator, tol):
"""Dispatches to appropriate function if bose_operator is a BoseWord or BoseSentence."""
raise ValueError(f"bose_operator must be a BoseWord or BoseSentence, got: {bose_operator}")


@_christiansen_mapping_dispatch.register
def _(bose_operator: BoseWord, tol=None):

qubit_operator = PauliSentence({PauliWord({}): 1.0})

coeffs = {"+": -0.5j, "-": 0.5j}

for (_, b_idx), sign in bose_operator.items():

qubit_operator @= PauliSentence(
{
PauliWord({**{b_idx: "X"}}): 0.5,
PauliWord({**{b_idx: "Y"}}): coeffs[sign],
}
)

for pw in qubit_operator:
if tol is not None and abs(qml.math.imag(qubit_operator[pw])) <= tol:
qubit_operator[pw] = qml.math.real(qubit_operator[pw])

qubit_operator.simplify(tol=1e-16)

return qubit_operator


@_christiansen_mapping_dispatch.register
def _(bose_operator: BoseSentence, tol=None):

qubit_operator = PauliSentence()

for bw, coeff in bose_operator.items():
bose_word_as_ps = christiansen_mapping(bw, ps=True)

for pw in bose_word_as_ps:
qubit_operator[pw] = qubit_operator[pw] + bose_word_as_ps[pw] * coeff

if tol is not None and abs(qml.math.imag(qubit_operator[pw])) <= tol:
qubit_operator[pw] = qml.math.real(qubit_operator[pw])

qubit_operator.simplify(tol=1e-16)

return qubit_operator
Loading

0 comments on commit b8d0b91

Please sign in to comment.