Skip to content

Commit

Permalink
Quantum gate models for IR integration (#16)
Browse files Browse the repository at this point in the history
* Add IR

* Move tests

* Run black

* Rename ir/ directories to xir/

* Apply formatter and update import paths

* Clarify that top-level makefile is for C++ code

* Rename Python bindings package to 'bindings'

* Move Python bindings tests to subdirectory

* Update import path to Python bindings module

* Rename 'requirements_test.txt' to 'requirements.txt'

* Add Python wheel dependencies

* Add Python distribution directory to .gitignore

* Create top-level Jet Python package

* Create setup.py to build quantum-jet Python wheels

* Move setup.py to python/ directory

* Make cleaned directory prefixes consistent

* Add 'build' help documentation and clean build/ and dist/

* Change source directory to parent directory

* Import all bindings directly into the 'jet' package

* Exclude tests from package

* Fix wheel build error for lark

* Remove deprecated Python bindings build steps

* Update changelog

* Adjust PR number

* Flatten jet.bindings package and apply formatter

* Change 'lark' requirement to 'lark-parser'

* add circuit class

* add first gate

* Add gates (WIP)

* add gates

* Add jet/ to formatted directories

* Refactor Gate class

* Apply formatter to jet/ directory

* Factor parameter validation to Gate class

* Remove positional arguments after keyword arguments

* Move dtype factories to separate module to avoid circular dependency

* Add unit tests for the Gate class

* Delegate package exports to modules

* Update name of validation parameter

* Add unit tests for H, CNOT, and Pauli gates

* Add unit tests for remaining gates

* Add unit test IDs

* Add unit tests for CV Fock gates

* Defer circuit.py to future PR

* Update changelog

* Add thewalrus to package requirements and specify numpy versions

* Create type aliases for union of template class specializations

* Convert Gate into an ABC, expose num_wires, and distribute validation

* Use MockGate instead of CPhaseShift in Gate tests

* Elaborate docstring comments

* Replace conjugate transpose with matrix inverse

* Replace MockGate data with invertible matrix

* Move parameter validation to gate constructors

* Rename 'gates.py' to 'gate.py'

* Reword @indices.getter docstring

* Remove leftover *params from Displacement constructor

* Import symbols from math and cmath modules explicitly

* Rename 'CNOT' gate to 'CX' gate

* Add aliases for NOT and CNOT gates

* Add code span formatting to None

Co-authored-by: antalszava <[email protected]>

* Add colon after Exception class in docstring

Co-authored-by: antalszava <[email protected]>

* Apply hanging indent to Exception description

Co-authored-by: antalszava <[email protected]>

* Update wording of num_wires attribute

Co-authored-by: antalszava <[email protected]>

* Remove full stop from docstring argument descriptions

* Restore full stop and capitalize argument descriptions

* Fix grammar error in transmissivity argument description

* Remove tensor ID (and **kwargs) from Gate (sub)class(es)

* Test multi-character string indices

* Add descriptions to *args and **kwargs

* Remove extra space from list

* Mention Antal and Josh in changelog

Co-authored-by: Mikhail Andrenkov <[email protected]>
Co-authored-by: Mikhail Andrenkov <[email protected]>
Co-authored-by: antalszava <[email protected]>
  • Loading branch information
4 people authored Jun 11, 2021
1 parent 681ba44 commit 760b11e
Show file tree
Hide file tree
Showing 7 changed files with 1,587 additions and 84 deletions.
6 changes: 4 additions & 2 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### New features since last release

* Quantum gate models have been added to the `jet` Python package. [(#16)](https://github.com/XanaduAI/jet/pull/16)

* Python bindings are now available for the `TaskBasedCpuContractor` class. [(#19)](https://github.com/XanaduAI/jet/pull/19)

* Python bindings now include a factory method which accepts a `dtype` parameter. [(#18)](https://github.com/XanaduAI/jet/pull/18)
Expand All @@ -22,7 +24,7 @@

* Tensor transposes are now significantly faster when all the dimensions are powers of two. [(#12)](https://github.com/XanaduAI/jet/pull/12)

* Use camel case for type aliases [(#17)](https://github.com/XanaduAI/jet/pull/17)
* Use camel case for type aliases. [(#17)](https://github.com/XanaduAI/jet/pull/17)

* Exceptions are now favoured in place of `std::terminate` with `Exception` being the new base type for all exceptions thrown by Jet. [(#3)](https://github.com/XanaduAI/jet/pull/3)

Expand Down Expand Up @@ -52,7 +54,7 @@

This release contains contributions from (in alphabetical order):

[Mikhail Andrenkov](https://github.com/Mandrenkov), [Jack Brown](https://github.com/brownj85), [Theodor Isacsson](https://github.com/thisac), [Lee J. O'Riordan](https://github.com/mlxd), [Trevor Vincent](https://github.com/trevor-vincent).
[Mikhail Andrenkov](https://github.com/Mandrenkov), [Jack Brown](https://github.com/brownj85), [Theodor Isacsson](https://github.com/thisac), [Josh Izaac](https://github.com/josh146), [Lee J. O'Riordan](https://github.com/mlxd), [Antal Száva](https://github.com/antalszava), [Trevor Vincent](https://github.com/trevor-vincent).

## Release 0.1.0 (current release)

Expand Down
8 changes: 4 additions & 4 deletions python/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ setup: $(.VENV_DIR)/touch
.PHONY: format
format: $(.VENV_DIR)/requirements.txt.touch
ifdef check
$(.VENV_BIN)/black -l 100 --check tests
$(.VENV_BIN)/isort --profile black --check-only tests
$(.VENV_BIN)/black -l 100 --check jet tests
$(.VENV_BIN)/isort --profile black --check-only jet tests
else
$(.VENV_BIN)/black -l 100 tests
$(.VENV_BIN)/isort --profile black tests
$(.VENV_BIN)/black -l 100 jet tests
$(.VENV_BIN)/isort --profile black jet tests
endif


Expand Down
80 changes: 3 additions & 77 deletions python/jet/__init__.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,9 @@
from typing import Union

import numpy as np

# The existence of a Python binding is proof of its intention to be exposed.
from .bindings import *


def TaskBasedCpuContractor(
*args, **kwargs
) -> Union[TaskBasedCpuContractorC64, TaskBasedCpuContractorC128]:
"""Constructs a task-based CPU contractor with the specified data type. If a
`dtype` keyword argument is not provided, a TaskBasedCpuContractorC128
instance will be returned.
"""
dtype = kwargs.pop("dtype", "complex128")
if np.dtype(dtype) == np.complex64:
return TaskBasedCpuContractorC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TaskBasedCpuContractorC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def Tensor(*args, **kwargs) -> Union[TensorC64, TensorC128]:
"""Constructs a tensor with the specified data type. If a `dtype` keyword
argument is not provided, a TensorC128 instance will be returned.
"""
dtype = kwargs.pop("dtype", "complex128")
if np.dtype(dtype) == np.complex64:
return TensorC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def TensorNetwork(*args, **kwargs) -> Union[TensorNetworkC64, TensorNetworkC128]:
"""Constructs a tensor network with the specified data type. If a `dtype`
keyword argument is not provided, a TensorNetworkC128 instance will be
returned.
"""
dtype = kwargs.pop("dtype", "complex128")
if np.dtype(dtype) == np.complex64:
return TensorNetworkC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorNetworkC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def TensorNetworkFile(*args, **kwargs) -> Union[TensorNetworkFileC64, TensorNetworkFileC128]:
"""Constructs a tensor network file with the specified data type. If a
`dtype` keyword argument is not provided, a TensorNetworkFileC128 instance
will be returned.
"""
dtype = kwargs.pop("dtype", "complex128")
if np.dtype(dtype) == np.complex64:
return TensorNetworkFileC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorNetworkFileC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def TensorNetworkSerializer(
*args, **kwargs
) -> Union[TensorNetworkSerializerC64, TensorNetworkSerializerC128]:
"""Constructs a tensor network serializer with the specified data type. If a
`dtype` keyword argument is not provided, a TensorNetworkSerializerC128
instance will be returned.
"""
dtype = kwargs.pop("dtype", "complex128")
if np.dtype(dtype) == np.complex64:
return TensorNetworkSerializerC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorNetworkSerializerC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")

# The rest of the modules control their exports using `__all__`.
from .factory import *
from .gate import *

# Grab the current Jet version from the C++ headers.
__version__ = version()
140 changes: 140 additions & 0 deletions python/jet/factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
from typing import Union

import numpy as np

from .bindings import (
TaskBasedCpuContractorC64,
TaskBasedCpuContractorC128,
TensorC64,
TensorC128,
TensorNetworkC64,
TensorNetworkC128,
TensorNetworkFileC64,
TensorNetworkFileC128,
TensorNetworkSerializerC64,
TensorNetworkSerializerC128,
)

__all__ = [
"TaskBasedCpuContractorType",
"TensorType",
"TensorNetworkType",
"TensorNetworkFileType",
"TensorNetworkSerializerType",
"TaskBasedCpuContractor",
"Tensor",
"TensorNetwork",
"TensorNetworkFile",
"TensorNetworkSerializer",
]

# Type aliases to avoid enumerating class specializations.
TaskBasedCpuContractorType = Union[TaskBasedCpuContractorC64, TaskBasedCpuContractorC128]
TensorType = Union[TensorC64, TensorC128]
TensorNetworkType = Union[TensorNetworkC64, TensorNetworkC128]
TensorNetworkFileType = Union[TensorNetworkFileC64, TensorNetworkFileC128]
TensorNetworkSerializerType = Union[TensorNetworkSerializerC64, TensorNetworkSerializerC128]


def TaskBasedCpuContractor(*args, **kwargs) -> TaskBasedCpuContractorType:
"""Constructs a task-based CPU contractor (TBCC) with the specified data
type. If a ``dtype`` keyword argument is not provided, a
``TaskBasedCpuContractorC128`` instance will be returned.
Args:
*args: Positional arguments to pass to the TBCC constructor.
**kwargs: Keyword arguments to pass to the TBCC constructor.
Returns:
Task-based CPU contractor instance.
"""
dtype = kwargs.pop("dtype", np.complex128)
if np.dtype(dtype) == np.complex64:
return TaskBasedCpuContractorC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TaskBasedCpuContractorC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def Tensor(*args, **kwargs) -> TensorType:
"""Constructs a tensor with the specified data type. If a ``dtype`` keyword
argument is not provided, a ``TensorC128`` instance will be returned.
Args:
*args: Positional arguments to pass to the tensor constructor.
**kwargs: Keyword arguments to pass to the tensor constructor.
Returns:
Tensor instance.
"""
dtype = kwargs.pop("dtype", np.complex128)
if np.dtype(dtype) == np.complex64:
return TensorC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def TensorNetwork(*args, **kwargs) -> TensorNetworkType:
"""Constructs a tensor network with the specified data type. If a ``dtype``
keyword argument is not provided, a ``TensorNetworkC128`` instance will be
returned.
Args:
*args: Positional arguments to pass to the tensor network constructor.
**kwargs: Keyword arguments to pass to the tensor network constructor.
Returns:
Tensor network instance.
"""
dtype = kwargs.pop("dtype", np.complex128)
if np.dtype(dtype) == np.complex64:
return TensorNetworkC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorNetworkC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def TensorNetworkFile(*args, **kwargs) -> TensorNetworkFileType:
"""Constructs a tensor network file with the specified data type. If a
``dtype`` keyword argument is not provided, a ``TensorNetworkFileC128``
instance will be returned.
Args:
*args: Positional arguments to pass to the tensor network file constructor.
**kwargs: Keyword arguments to pass to the tensor network file constructor.
Returns:
Tensor network file instance.
"""
dtype = kwargs.pop("dtype", np.complex128)
if np.dtype(dtype) == np.complex64:
return TensorNetworkFileC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorNetworkFileC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")


def TensorNetworkSerializer(*args, **kwargs) -> TensorNetworkSerializerType:
"""Constructs a tensor network serializer with the specified data type. If a
``dtype`` keyword argument is not provided, a ``TensorNetworkSerializerC128``
instance will be returned.
Args:
*args: Positional arguments to pass to the tensor network serializer constructor.
**kwargs: Keyword arguments to pass to the tensor network serializer constructor.
Returns:
Tensor network serializer instance.
"""
dtype = kwargs.pop("dtype", np.complex128)
if np.dtype(dtype) == np.complex64:
return TensorNetworkSerializerC64(*args, **kwargs)
elif np.dtype(dtype) == np.complex128:
return TensorNetworkSerializerC128(*args, **kwargs)
else:
raise TypeError(f"Data type '{dtype}' is not supported.")
Loading

0 comments on commit 760b11e

Please sign in to comment.