import numpy as np
from typing import Optional, List
from .generic import MeshNumpyLayer, MeshPhases
from ..config import DEFAULT_BASIS
from ..meshmodel import RectangularMeshModel, TriangularMeshModel, PermutingRectangularMeshModel, ButterflyMeshModel
from ..helpers import grid_viz_permutation
[docs]class RMNumpy(MeshNumpyLayer):
def __init__(self, units: int, num_layers: int = None, hadamard: bool = False, basis: str = DEFAULT_BASIS,
bs_error: float = 0.0, theta_init="haar_rect",
phi_init="random_phi", gamma_init="random_gamma"):
"""Rectangular mesh network layer for unitary operators implemented in numpy
Args:
units: The dimension of the unitary matrix (:math:`N`)
num_layers: The number of layers (:math:`L`) of the mesh
hadamard: Hadamard convention for the beamsplitters
basis: Phase basis to use
bs_error: Beamsplitter split ratio error
theta_init: Initializer name for :code:`theta` (:math:`\\boldsymbol{\\theta}` or :math:`\\theta_{n\ell}`)
phi_init: Initializer name for :code:`phi` (:math:`\\boldsymbol{\\phi}` or :math:`\\phi_{n\ell}`)
gamma_init: Initializer name for :code:`gamma` (:math:`\\boldsymbol{\\gamma}` or :math:`\\gamma_{n}`)
"""
super(RMNumpy, self).__init__(
RectangularMeshModel(units, num_layers, hadamard, bs_error, basis,
theta_init, phi_init, gamma_init)
)
[docs] def propagate(self, inputs: np.ndarray, explicit: bool = False,
viz_perm_idx: Optional[np.ndarray] = None) -> np.ndarray:
viz_perm_idx = grid_viz_permutation(self.units, self.num_layers,
flip=explicit) if viz_perm_idx is None else viz_perm_idx
# viz_perm_idx = None
return super(RMNumpy, self).propagate(inputs, explicit, viz_perm_idx)
[docs] def inverse_propagate(self, inputs: np.ndarray, explicit: bool = False,
viz_perm_idx: Optional[np.ndarray] = None) -> np.ndarray:
viz_perm_idx = grid_viz_permutation(self.units, self.num_layers,
flip=explicit) if viz_perm_idx is None else viz_perm_idx
# viz_perm_idx = None
return super(RMNumpy, self).inverse_propagate(inputs, explicit, viz_perm_idx)
[docs]class TMNumpy(MeshNumpyLayer):
def __init__(self, units: int, hadamard: bool = False, basis: str = DEFAULT_BASIS,
bs_error: float = 0.0,
theta_init="haar_tri", phi_init="random_phi", gamma_init="random_gamma"):
"""Triangular mesh network layer for unitary operators implemented in numpy
Args:
units: The dimension of the unitary matrix (:math:`N`)
hadamard: Hadamard convention for the beamsplitters
basis: Phase basis to use
bs_error: Beamsplitter split ratio error
"""
super(TMNumpy, self).__init__(
TriangularMeshModel(units, hadamard, bs_error, basis,
theta_init, phi_init, gamma_init)
)
[docs] def propagate(self, inputs: np.ndarray, explicit: bool = False,
viz_perm_idx: Optional[np.ndarray] = None) -> np.ndarray:
viz_perm_idx = grid_viz_permutation(self.units, self.num_layers) if viz_perm_idx is None else viz_perm_idx
return super(TMNumpy, self).propagate(inputs, explicit, viz_perm_idx)
[docs] def inverse_propagate(self, inputs: np.ndarray, explicit: bool = False,
viz_perm_idx: Optional[np.ndarray] = None) -> np.ndarray:
viz_perm_idx = grid_viz_permutation(self.units, self.num_layers) if viz_perm_idx is None else viz_perm_idx
return super(TMNumpy, self).inverse_propagate(inputs, explicit, viz_perm_idx)
[docs]class BMNumpy(MeshNumpyLayer):
def __init__(self, num_layers: int, basis: str = DEFAULT_BASIS,
bs_error: float = 0.0, hadamard: bool = False, theta_init: Optional[str] = 'random_theta',
phi_init: Optional[str] = 'random_phi'):
"""Butterfly mesh unitary layer (currently, only :math:`2^L` units allowed)
Args:
num_layers: The number of layers (:math:`L`), with dimension of the unitary matrix set to (:math:`N = 2^L`)
bs_error: Photonic error in the beamsplitter
hadamard: Hadamard convention for the beamsplitters
theta_init: Initializer name for :code:`theta` (:math:`\\boldsymbol{\\theta}` or :math:`\\theta_{n\ell}`)
phi_init: Initializer name for :code:`phi` (:math:`\\boldsymbol{\\phi}` or :math:`\\phi_{n\ell}`)
"""
super(BMNumpy, self).__init__(
ButterflyMeshModel(num_layers, hadamard, bs_error, basis, theta_init, phi_init)
)
[docs]class PRMNumpy(MeshNumpyLayer):
def __init__(self, units: int, tunable_layers_per_block: int = None,
num_tunable_layers_list: Optional[List[int]] = None, sampling_frequencies: Optional[List[int]] = None,
bs_error: float = 0.0, hadamard: bool = False, theta_init: Optional[str] = 'haar_prm',
phi_init: Optional[str] = 'random_phi'):
"""Permuting rectangular mesh unitary layer
Args:
units: The dimension of the unitary matrix (:math:`N`) to be modeled by this transformer
tunable_layers_per_block: The number of tunable layers per block (overrides `num_tunable_layers_list`, `sampling_frequencies`)
num_tunable_layers_list: Number of tunable layers in each block in order from left to right
sampling_frequencies: Frequencies of sampling frequencies between the tunable layers
bs_error: Photonic error in the beamsplitter
hadamard: Hadamard convention for the beamsplitters
theta_init: Initializer name for :code:`theta` (:math:`\\boldsymbol{\\theta}` or :math:`\\theta_{n\ell}`)
phi_init: Initializer name for :code:`phi` (:math:`\\boldsymbol{\\phi}` or :math:`\\phi_{n\ell}`)
"""
if theta_init == 'haar_prm' and tunable_layers_per_block is not None:
raise NotImplementedError('haar_prm initializer is incompatible with setting tunable_layers_per_block.')
super(PRMNumpy, self).__init__(
PermutingRectangularMeshModel(units, tunable_layers_per_block, num_tunable_layers_list,
sampling_frequencies, bs_error, hadamard,
theta_init, phi_init)
)