Source code for mrmustard.lab.circuit
# Copyright 2021 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.
"""
This module implements the :class:`.Circuit` class which acts as a representation for quantum circuits.
"""
from __future__ import annotations
__all__ = ["Circuit"]
from typing import List, Optional, Tuple
from mrmustard import settings
from mrmustard.lab.abstract import State, Transformation
from mrmustard.utils.typing import RealMatrix, RealVector
from mrmustard.lab.circuit_drawer import circuit_text
from mrmustard.math.tensor_wrappers import XPMatrix, XPVector
import numpy as np
[docs]
class Circuit(Transformation):
"""Represents a quantum circuit: a set of operations to be applied on quantum states.
Args:
ops (list or none): A list of operations comprising the circuit.
"""
def __init__(self, ops: Optional[List] = None):
self._ops = list(ops) if ops is not None else []
super().__init__(name="Circuit")
self.reset()
@property
def ops(self) -> Optional[List]:
r"""
The list of operations comprising the circuit.
"""
return self._ops
[docs]
def reset(self):
"""Resets the state of the circuit clearing the list of modes and setting the compiled flag to false."""
self._compiled: bool = False
self._modes: List[int] = []
@property
def num_modes(self) -> int:
all_modes = {mode for op in self._ops for mode in op.modes}
return len(all_modes)
[docs]
def primal(self, state: State) -> State:
for op in self._ops:
state = op.primal(state)
return state
[docs]
def dual(self, state: State) -> State:
for op in reversed(self._ops):
state = op.dual(state)
return state
[docs]
def XYd(
self,
allow_none: bool = True,
) -> Tuple[
RealMatrix, RealMatrix, RealVector
]: # NOTE: Overriding Transformation.XYd for efficiency
X = XPMatrix(like_1=True)
Y = XPMatrix(like_0=True)
d = XPVector()
for op in self._ops:
opx, opy, opd = op.XYd(allow_none)
opX = XPMatrix.from_xxpp(opx, modes=(op.modes, op.modes), like_1=True)
opY = XPMatrix.from_xxpp(opy, modes=(op.modes, op.modes), like_0=True)
opd = XPVector.from_xxpp(opd, modes=op.modes)
if opX.shape is not None and opX.shape[-1] == 1 and len(op.modes) > 1:
opX = opX.clone(len(op.modes), modes=(op.modes, op.modes))
if opY.shape is not None and opY.shape[-1] == 1 and len(op.modes) > 1:
opY = opY.clone(len(op.modes), modes=(op.modes, op.modes))
if opd.shape is not None and opd.shape[-1] == 1 and len(op.modes) > 1:
opd = opd.clone(len(op.modes), modes=op.modes)
X = opX @ X
Y = opX @ Y @ opX.T + opY
d = opX @ d + opd
return X.to_xxpp(), Y.to_xxpp(), d.to_xxpp()
@property
def is_gaussian(self):
"""Returns `true` if all operations in the circuit are Gaussian."""
return all(op.is_gaussian for op in self._ops)
@property
def is_unitary(self):
"""Returns `true` if all operations in the circuit are unitary."""
return all(op.is_unitary for op in self._ops)
def __len__(self):
return len(self._ops)
_repr_markdown_ = None
def __repr__(self) -> str:
"""String to display the object on the command line."""
# ops_repr = [repr(op) for op in self._ops]
# return " >> ".join(ops_repr)
return circuit_text(self._ops, decimals=settings.CIRCUIT_DECIMALS)
def __str__(self):
"""String representation of the circuit."""
ops_repr = [repr(op) for op in self._ops]
return " >> ".join(ops_repr)
# pylint: disable=too-many-branches,too-many-return-statements
def __eq__(self, other):
r"""Returns ``True`` if the two transformations are equal."""
if not isinstance(other, Circuit):
return False
if not (self.is_gaussian and other.is_gaussian):
return np.allclose(
self.choi(cutoffs=[settings.EQ_TRANSFORMATION_CUTOFF] * 4 * self.num_modes),
other.choi(cutoffs=[settings.EQ_TRANSFORMATION_CUTOFF] * 4 * self.num_modes),
rtol=settings.EQ_TRANSFORMATION_RTOL_FOCK,
)
sX, sY, sd = self.XYd(allow_none=False)
oX, oY, od = other.XYd(allow_none=False)
return np.allclose(sX, oX) and np.allclose(sY, oY) and np.allclose(sd, od)
_modules/mrmustard/lab/circuit
Download Python script
Download Notebook
View on GitHub