Source code for jet.state
"""Module containing the ``State`` class in addition to all ``State`` subclasses."""
from abc import ABC, abstractmethod
from typing import List, Optional, Sequence
import numpy as np
from .factory import Tensor, TensorType
__all__ = [
"State",
"Qudit",
"QuditRegister",
"Qubit",
"QubitRegister",
]
[docs]class State(ABC):
"""State represents a quantum state.
Args:
name (str): Name of the state.
num_wires (str): Number of wires the state is connected to.
"""
def __init__(self, name: str, num_wires: int):
self.name = name
self._indices = None
self._num_wires = num_wires
@property
def indices(self) -> Optional[List[str]]:
"""Returns the indices of this state. An index is a label associated with
an axis of the tensor representation of a state; the indices of a tensor
determine its connectivity in the context of a tensor network.
"""
return self._indices
@indices.setter
def indices(self, indices: Optional[Sequence[str]]) -> None:
"""Sets the indices of this state. The ``indices`` property of a state
is used to construct its tensor representation (unless ``indices`` is
None). See @indices.getter for more information about tensor indices.
Raises:
ValueError: If the given indices are not a sequence of unique
strings or the number of provided indices is invalid.
Args:
indices (Sequence[str] or None): New indices of the state.
"""
# Skip the sequence property checks if `indices` is None.
if indices is None:
pass
# Check that `indices` is a sequence of unique strings.
elif (
not isinstance(indices, Sequence)
or not all(isinstance(idx, str) for idx in indices)
or len(set(indices)) != len(indices)
):
raise ValueError("Indices must be a sequence of unique strings.")
# Check that `indices` has the correct length (or is None).
elif len(indices) != self.num_wires:
raise ValueError(
f"States must have one index per wire. "
f"Received {len(indices)} indices for {self.num_wires} wires."
)
self._indices = indices
@property
def num_wires(self) -> int:
"""Returns the number of wires connected to this state."""
return self._num_wires
def __eq__(self, other) -> bool:
"""Reports whether this state is equivalent to the given state."""
return np.all(self._data() == other._data())
def __ne__(self, other) -> bool:
"""Reports whether this state is not equivalent to the given state."""
return not self == other
@abstractmethod
def _data(self) -> np.ndarray:
"""Returns the vector representation of this state."""
[docs] def tensor(self, dtype: np.dtype = np.complex128) -> TensorType:
"""Returns the tensor representation of this state.
Args:
dtype (np.dtype): Data type of the tensor.
"""
data = self._data()
indices = self.indices
if indices is None:
indices = list(map(str, range(self.num_wires)))
dimension = int(round(len(data) ** (1 / len(indices))))
shape = [dimension] * len(indices)
return Tensor(indices=indices, shape=shape, data=data, dtype=dtype)
[docs]class Qudit(State):
"""Qudit represents a qudit state.
Args:
dim (int): Dimension of the qudit.
data (np.ndarray or None): Optional state vector.
"""
def __init__(self, dim: int, data: Optional[np.ndarray] = None):
name = "Qubit" if dim == 2 else f"Qudit(d={dim})"
super().__init__(name=name, num_wires=1)
if data is None:
self._state_vector = (np.arange(dim) == 0).astype(np.complex128)
else:
self._state_vector = data.flatten()
def _data(self) -> np.ndarray:
return self._state_vector
[docs]class QuditRegister(State):
"""QuditRegister represents a qudit register state.
Args:
dim (int): Dimension of the qudits.
size (int): Number of qudits.
data (np.ndarray or None): Optional state vector.
"""
def __init__(self, dim: int, size: int, data: Optional[np.ndarray] = None):
name = f"Qubit[{size}]" if dim == 2 else f"Qudit(d={dim})[{size}]"
super().__init__(name=name, num_wires=size)
if data is None:
self._state_vector = (np.arange(dim**size) == 0).astype(np.complex128)
else:
self._state_vector = data.flatten()
def _data(self) -> np.ndarray:
return self._state_vector
[docs]def Qubit(data: Optional[np.ndarray] = None) -> Qudit:
"""Constructs a qubit state using an optional state vector.
Args:
data (np.ndarray or None): Optional state vector.
Returns:
Qudit: Qudit with the specified state vector.
"""
return Qudit(dim=2, data=data)
[docs]def QubitRegister(size: int, data: Optional[np.ndarray] = None) -> QuditRegister:
"""Constructs a qubit register state with the given size and optional state vector.
Args:
size (int): Number of qubits.
data (np.ndarray or None): Optional state vector.
Returns:
QuditRegister: QuditRegister with the specified state vector.
"""
return QuditRegister(dim=2, size=size, data=data)
_modules/jet/state
Download Python script
Download Notebook
View on GitHub