Skip to content

Commit

Permalink
Merge pull request #2 from XanaduAI/nearest_neighbour
Browse files Browse the repository at this point in the history
Added support for Bose-Hubbard propagation with nearest-neighbour interactions
  • Loading branch information
josh146 committed Sep 26, 2018
2 parents 986b9b9 + 47f6d8f commit 2f87f67
Show file tree
Hide file tree
Showing 12 changed files with 344 additions and 55 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
language: python
cache: pip
python:
- 3.5
- 3.6
env:
- LOGGING=info
install:
- pip install -r requirements.txt
- pip install wheel codecov
Expand Down
18 changes: 10 additions & 8 deletions doc/bosehubbard.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. role:: raw-latex(raw)
:format: latex

.. role:: html(raw)
:format: html

Expand Down Expand Up @@ -33,28 +33,31 @@ where:
CV decomposition
----------------

As the Bose-Hubbard Hamiltonian is time-independent, it suffices to find a continuous-variable (CV) gate decomposition for the unitary operator :math:`\hat{U}=e^{-i\hat{H}t}` :cite:`kalajdzievski2018`. Let's consider the case :math:`V=0` (i.e., no nearest-neighbour interactions). In this case, we can rewrite the Hamiltonian in the following form:
As the Bose-Hubbard Hamiltonian is time-independent, it suffices to find a continuous-variable (CV) gate decomposition for the unitary operator :math:`\hat{U}=e^{-i\hat{H}t}` :cite:`kalajdzievski2018`. We can rewrite the Hamiltonian in the following form:


.. math::
\hat{H} = -J\sum_{i=1}^N\sum_{j=1}^N A_{ij} \ad_i\a_j
+ \sum_{\ell=1}^N \left(\frac{1}{2}U \hat{n}_\ell^2
- \left(\frac{1}{2}U+\mu\right) \hat{n}_\ell\right),
- \left(\frac{1}{2}U+\mu\right) \hat{n}_\ell\right)
+ V \sum_{i=1}^N\sum_{j=1}^N \hat{n}_i\hat{n}_j,
where :math:`\hat{n}_i=\ad_i\a_i` is the bosonic number operator. Taking the matrix exponential, and applying the Lie product formula,

.. math::
e^{-iHt} = \lim_{k\rightarrow\infty}\left[\prod_{\substack{i,j\\i\sim j}}\exp\left({i\frac{ J t}{k}(\ad_i\a_j + \ad_j\a_i)}\right)\prod_{\ell}\exp\left(-i\frac{Ut}{2k}\hat{n}_\ell^2\right)\exp\left(i\frac{(U+2\mu)t}{2k}\hat{n}_\ell\right)\right]^k,
e^{-iHt} = \lim_{k\rightarrow\infty}\left[\prod_{\substack{i,j\\i\sim j}}\exp\left({i\frac{ J t}{k}(\ad_i\a_j + \ad_j\a_i)}\right)\exp\left({-i\frac{V t}{k}\hat{n}_i\hat{n}_j}\right)\prod_{\ell}\exp\left(-i\frac{Ut}{2k}\hat{n}_\ell^2\right)\exp\left(i\frac{(U+2\mu)t}{2k}\hat{n}_\ell\right)\right]^k,
where :math:`i\sim j` indicates we are only summing over adjacent nodes (i.e., those where :math:`A_{ij}=1`). Truncating :math:`k` to a reasonable value, we end up with the approximation

.. math::
e^{-iHt} = \left[\prod_{\substack{i,j\\i\sim j}}\exp\left({i\frac{ J t}{k}(\ad_i\a_j + \ad_j\a_i)}\right)\prod_{\ell}\exp\left(-i\frac{Ut}{2k}\hat{n}_\ell^2\right)\exp\left(i\frac{(U+2\mu)t}{2k}\hat{n}_\ell\right)\right]^k + \mathcal{O}(t^2/k).
e^{-iHt} = \left[\prod_{\substack{i,j\\i\sim j}}\exp\left({i\frac{ J t}{k}(\ad_i\a_j + \ad_j\a_i)}\right)\exp\left({-i\frac{V t}{k}\hat{n}_i\hat{n}_j}\right)\prod_{\ell}\exp\left(-i\frac{Ut}{2k}\hat{n}_\ell^2\right)\exp\left(i\frac{(U+2\mu)t}{2k}\hat{n}_\ell\right)\right]^k + \mathcal{O}(t^2/k).
Comparing these individual bracketed operators with the known CV gate set (see `here <https://strawberryfields.readthedocs.io/en/latest/conventions/gates.html>`_ for more details) we see that they correspond to a beamsplitter, Kerr gate, and phase-space rotation respectively:
Comparing these individual bracketed operators with the known CV gate set (see `here <https://strawberryfields.readthedocs.io/en/latest/conventions/gates.html>`_ for more details) we see that they correspond to a beamsplitter, cross-Kerr gate, Kerr gate, and phase-space rotation respectively:

* :math:`\exp\left({i\frac{ J t}{k}(\ad_i\a_j + \ad_j\a_i)}\right)\equiv BS(\theta, \phi)` where :math:`\theta=Jt/k`, :math:`\phi=\pi/2`,

* :math:`\exp\left({-i\frac{V t}{k}\hat{n}_i\hat{n}_j}\right)\equiv CK(\kappa)` where :math:`\kappa=-Vt/k`,

* :math:`\exp\left(-i\frac{Ut}{2k}\hat{n}_\ell^2\right)\equiv K(\kappa)` where :math:`\kappa=-Ut/2k`,

* :math:`\exp\left(i\frac{(U+2\mu)t}{2k}\hat{n}_\ell\right)\equiv R(r)` where :math:`r=(U+2\mu)t/2k`.
Expand All @@ -64,10 +67,9 @@ Comparing these individual bracketed operators with the known CV gate set (see `
.. admonition:: Decomposition
:class: defn

A Bose-Hubbard Hamiltonian with zero nearest-neighbour interactions can be implemented to arbitrary error via a decomposition of beamsplitters, Kerr gates, and phase-space rotations.
A Bose-Hubbard Hamiltonian can be implemented to arbitrary error via a decomposition of beamsplitters, cross-Kerr interactions, Kerr gates, and phase-space rotations.

.. tip::

*Implemented in SFOpenBoson as a quantum operation by* :class:`sfopenboson.ops.BoseHubbardPropagation`


2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
requirements = [
"numpy>=1.13",
"scipy>=1.0.0",
"strawberryfields>=0.7.3",
"strawberryfields>=0.8.0",
"openfermion>=0.7"
]

Expand Down
2 changes: 1 addition & 1 deletion sfopenboson/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = '0.1.1'
__version__ = '0.2.0'
12 changes: 9 additions & 3 deletions sfopenboson/auxillary.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ def extract_tunneling(H):
if len(set(BS.values())) != 1:
raise BoseHubbardError

return [list(BS.keys()), -t]
# check t is real
if t.imag != 0:
raise BoseHubbardError

return [list(BS.keys()), -t.real]


def extract_onsite_chemical(H):
Expand Down Expand Up @@ -328,6 +332,8 @@ def trotter_layer(H, t, k):
``kappa`` acting on the list of modes provided.
* ``'R': (r, modes)`` corresponding to rotation gates with parameter
``r`` acting on the list of modes provided.
* ``'CK': (kappa, modes)`` corresponding to a cross-Kerr interactions with parameter
``kappa`` acting on the list of modes provided.
"""
try:
BS = extract_tunneling(H)
Expand Down Expand Up @@ -358,7 +364,7 @@ def trotter_layer(H, t, k):
layer_dict['R'] = (t*U/(2*k), onsite[0])

if dipole:
raise BoseHubbardError("Nearest-neighbour or dipole interactions "
"not currently supported.")
V = dipole[1]
layer_dict['CK'] = (-t*V/k, dipole[0])

return layer_dict
37 changes: 27 additions & 10 deletions sfopenboson/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
from openfermion.utils import is_hermitian, prune_unused_indices

from strawberryfields.ops import (BSgate,
CKgate,
Decomposition,
GaussianTransform,
Kgate,
Expand Down Expand Up @@ -138,7 +139,7 @@ class GaussianPropagation(Decomposition):
"""
ns = None
def __init__(self, operator, t=1, mode='local', hbar=None):
super().__init__([t, operator])
super().__init__([t])

try:
# pylint: disable=protected-access
Expand Down Expand Up @@ -243,8 +244,6 @@ class BoseHubbardPropagation(Decomposition):
Lie-product formula, and decomposing the unitary operations into a combination
of beamsplitters, Kerr gates, and phase-space rotations.
.. note:: Nearest-neighbour interactions (:math:`V\neq 0`) are not currently supported.
Args:
operator (BosonOperator, QuadOperator): a bosonic Gaussian Hamiltonian
t (float): the time propagation value. If not provided, default value is 1.
Expand All @@ -259,7 +258,7 @@ class BoseHubbardPropagation(Decomposition):
"""
ns = None
def __init__(self, operator, t=1, k=20, mode='local', hbar=None):
super().__init__([t, operator])
super().__init__([t])

try:
# pylint: disable=protected-access
Expand Down Expand Up @@ -302,22 +301,40 @@ def decompose(self, reg):
phi = self.layer['BS'][1]
BS = BSgate(theta, phi)

# make cross-Kerr gate
CK = None
param = self.layer.get('CK', [0])[0]
if param != 0:
CK = CKgate(param)

# make Kerr gate
K = Kgate(self.layer['K'][0])
K = None
param = self.layer.get('K', [0])[0]
if param != 0:
K = Kgate(param)

# make rotation gate
R = Rgate(self.layer['R'][0])
R = None
param = self.layer.get('R', [0])[0]
if param != 0:
R = Rgate(param)

cmds = []

for i in range(self.num_layers): #pylint: disable=unused-variable
for q0, q1 in self.layer['BS'][2]:
cmds.append(Command(BS, (reg[q0], reg[q1])))

for mode in self.layer['K'][1]:
cmds.append(Command(K, reg[mode]))
if CK is not None:
for q0, q1 in self.layer['CK'][1]:
cmds.append(Command(CK, (reg[q0], reg[q1])))

if K is not None:
for mode in self.layer['K'][1]:
cmds.append(Command(K, reg[mode]))

for mode in self.layer['R'][1]:
cmds.append(Command(R, reg[mode]))
if R is not None:
for mode in self.layer['R'][1]:
cmds.append(Command(R, reg[mode]))

return cmds
1 change: 1 addition & 0 deletions sfopenboson/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test module""" # pragma: no cover
from .defaults import BaseTest
35 changes: 35 additions & 0 deletions sfopenboson/tests/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2018 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.
"""Test defaults"""
import logging
import os

import unittest

# Set the logging based on an environment variable.
# default logging is set to WARNING.
logLevel = os.environ.get("LOGGING", "WARNING")
numeric_level = getattr(logging, logLevel.upper(), 10)


logging.basicConfig(level=numeric_level, format='\n%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S')
logging.captureWarnings(True)


class BaseTest(unittest.TestCase):
"""The base unit test class used by SFOpenBoson"""

def logTestName(self):
"""Log the test method name at the information level"""
logging.info('%s', self.id())
Loading

0 comments on commit 2f87f67

Please sign in to comment.