Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## [1.0.0] - 2026-02-10
### Initial release
6 changes: 3 additions & 3 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cff-version: 0.0.0
cff-version: 1.0.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Girouard"
Expand All @@ -7,8 +7,8 @@ authors:
- family-names: "Quesada"
given-names: "Nicolás"
orcid: "https://orcid.org/0000-0002-0175-1688"
title: "Unitary-Decomp"
version: 0.0.0
title: "UDecomp"
version: 1.0.0
doi: 10.1364/JOSAB.577579
date-released: 2025-08-28
url: "https://github.com/polyquantique/Unitary-Decomp"
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![a](https://img.shields.io/static/v1?label=arXiv&message=2508.20010&color=active&style=flat-square)](https://arxiv.org/abs/arXiv:2508.20010)

# Unitary-Decomp
# UDecomp

Decomposition and approximation tools for linear optical unitaries.

Expand All @@ -17,7 +17,7 @@ Decomposition and approximation tools for linear optical unitaries.

## About This Project

`Unitary-Decomp` is a **Python** package for performing various **decompositions** and **approximations** of unitary matrices into planar arrangements of simple optical components. These tools can be used to design and program **universal multiport interferometers** (UMIs), devices capable of implementing arbitrary linear transformations on multiple optical modes. Such devices have numerous applications in communication, imaging, and information processing.
`UDecomp` is a **Python** package for performing various **decompositions** and **approximations** of unitary matrices into planar arrangements of simple optical components. These tools can be used to design and program **universal multiport interferometers** (UMIs), devices capable of implementing arbitrary linear transformations on multiple optical modes. Such devices have numerous applications in communication, imaging, and information processing.

The algorithms implemented in this package cover two main classes of planar UMI architectures:
- [Networks of two-mode components](#two-mode-component-networks)
Expand Down Expand Up @@ -47,30 +47,30 @@ Sequence of phase masks interleaved with the discrete Fourier transform mixing l
`Unitary-Decomp` provides tools to perform **exact decompositions** and **numerical approximations** of unitary matrices.

### Exact Decompositions
`Unitary-Decomp` includes four main modules to perform exact decompositions of unitary matrices:
`UDecomp` includes four main modules to perform exact decompositions of unitary matrices:

- [`clements_interferometer`](src/unitary_decomp/clements_interferometer.py): Implementation of the algorithm by [Clements *et al.*, 2016](https://doi.org/10.1364/OPTICA.3.001460) to decompose $N \times N$ unitary matrices into a rectangular mesh of $N(N-1)/2$ **asymmetric** Mach–Zehnder interferometers.
- [`clements_interferometer`](src/udecomp/clements_interferometer.py): Implementation of the algorithm by [Clements *et al.*, 2016](https://doi.org/10.1364/OPTICA.3.001460) to decompose $N \times N$ unitary matrices into a rectangular mesh of $N(N-1)/2$ **asymmetric** Mach–Zehnder interferometers.

- [`bell_interferometer`](src/unitary_decomp/bell_interferometer.py): Implementation of the algorithm by [Bell *et al.*, 2021](https://doi.org/10.1063/5.0053421) to decompose $N \times N$ unitary matrices into a rectangular mesh of $N(N-1)/2$ **symmetric** Mach–Zehnder interferometers.
- [`bell_interferometer`](src/udecomp/bell_interferometer.py): Implementation of the algorithm by [Bell *et al.*, 2021](https://doi.org/10.1063/5.0053421) to decompose $N \times N$ unitary matrices into a rectangular mesh of $N(N-1)/2$ **symmetric** Mach–Zehnder interferometers.

- [`lplm_interferometer`](src/unitary_decomp/lplm_interferometer.py): Implementation of the algorithm by [López Pastor *et al.*, 2021](https://doi.org/10.1364/OE.432787) to decompose $N \times N$ unitary matrices into a sequence of $6N+1$ phase masks interleaved with the **DFT** matrix.
- [`lplm_interferometer`](src/udecomp/lplm_interferometer.py): Implementation of the algorithm by [López Pastor *et al.*, 2021](https://doi.org/10.1364/OE.432787) to decompose $N \times N$ unitary matrices into a sequence of $6N+1$ phase masks interleaved with the **DFT** matrix.

- [`fourier_interferometer`](src/unitary_decomp/fourier_interferometer.py): Implementation of the **Fourier decomposition** and the **compact Fourier decomposition** to decompose $N \times N$ unitary matrices into sequences of $4N+1$ and $2N+5$ phase masks interleaved with **DFT** respectively.
- [`fourier_interferometer`](src/udecomp/fourier_interferometer.py): Implementation of the **Fourier decomposition** and the **compact Fourier decomposition** to decompose $N \times N$ unitary matrices into sequences of $4N+1$ and $2N+5$ phase masks interleaved with **DFT** respectively.

### Optimization Tools

In addition to exact decompositions, `Unitary-Decomp` also has an `optimization` subpackage, which contains tools to approximate unitary matrices into a sequence of phase masks interleaved with a chosen mixing layer. The `optimization` subpackage has two modules:
In addition to exact decompositions, `UDecomp` also has an `optimization` subpackage, which contains tools to approximate unitary matrices into a sequence of phase masks interleaved with a chosen mixing layer. The `optimization` subpackage has two modules:

- [`fourier_optimizer`](src/unitary_decomp/optimization/fourier_optimizer.py): Uses the basin-hopping algorithm from `scipy.optimize` to solve a global minimization problem, yielding the sequence of phase masks that minimizes the infidelity with respect to a target unitary.
- [`fourier_optimizer`](src/udecomp/optimization/fourier_optimizer.py): Uses the basin-hopping algorithm from `scipy.optimize` to solve a global minimization problem, yielding the sequence of phase masks that minimizes the infidelity with respect to a target unitary.

- [`jax_optimizer`](src/unitary_decomp/optimization/jax_optimizer.py): Uses `Jax` and `Optax` to perform gradient-based optimization of the phase masks with multiple restarts to minimize the infidelity with respect to a target unitary. This algorithm can run efficiently on CPU or GPU and is significantly faster than the SciPy-based implementation.
- [`jax_optimizer`](src/udecomp/optimization/jax_optimizer.py): Uses `Jax` and `Optax` to perform gradient-based optimization of the phase masks with multiple restarts to minimize the infidelity with respect to a target unitary. This algorithm can run efficiently on CPU or GPU and is significantly faster than the SciPy-based implementation.

---
**Note:** For more detailed descriptions and usage examples, see the documentation of the individual modules.

## Installation

You can install `Unitary-Decomp` from source as follows:
You can install `UDecomp` from source as follows:

1. Clone the repository

Expand Down Expand Up @@ -127,7 +127,7 @@ pytest tests
This first example shows how to use the `clements_interferometer` module to decompose a random unitary matrix.

```python
>>> from unitary_decomp import clements_interferometer as ci
>>> from udecomp import clements_interferometer as ci
>>> from scipy.stats import unitary_group
>>> import numpy as np
```
Expand Down Expand Up @@ -168,7 +168,7 @@ True
This example shows how to use the `fourier_interferometer` module to decompose a random unitary matrix.

```python
>>> from unitary_decomp import fourier_interferometer as fi
>>> from udecomp import fourier_interferometer as fi
>>> from scipy.stats import unitary_group
>>> import numpy as np
```
Expand Down Expand Up @@ -212,7 +212,7 @@ True
This example shows how to use the `jax_optimizer` module found in the `optimization` subpackage to find numerically a sequence of phase masks that approximate a given unitary matrix.

```python
>>> from unitary_decomp.optimize import jax_optimizer as jo
>>> from udecomp.optimize import jax_optimizer as jo
>>> from scipy.stats import unitary_group
>>> import numpy as np
```
Expand Down Expand Up @@ -244,7 +244,7 @@ The final matrix can be reconstructed using the `circuit_reconstruction` functio

## Documentation

The **LPLM algorithm** found in the [`lplm_interferometer`](src/unitary_decomp/lplm_interferometer.py) module was adapted from [López Pastor *et al.*, 2021](https://doi.org/10.1364/OE.432787) and uses a slightly different sequence of phase masks than the original paper. A comprehensive derivation of this new sequence can be found in the following document:
The **LPLM algorithm** found in the [`lplm_interferometer`](src/udecomp/lplm_interferometer.py) module was adapted from [López Pastor *et al.*, 2021](https://doi.org/10.1364/OE.432787) and uses a slightly different sequence of phase masks than the original paper. A comprehensive derivation of this new sequence can be found in the following document:

- [Decomposition of Unitary Matrices Using Fourier
Transforms and Phase Masks](papers/LPLM_algorithm_derivation.pdf)
Expand Down
2 changes: 1 addition & 1 deletion examples/clements_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import numpy as np

from unitary_decomp.clements_interferometer import circuit_reconstruction, clements_decomposition
from udecomp.clements_interferometer import circuit_reconstruction, clements_decomposition

# Example unitary matrix (U = H \otimes H)
U = 1 / 2 * np.array([[1, 1, 1, 1], [1, -1, 1, -1], [1, 1, -1, -1], [1, -1, -1, 1]])
Expand Down
8 changes: 4 additions & 4 deletions examples/fourier_decomposition.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"id": "c149d137",
"metadata": {},
"outputs": [],
"source": [
"# Import dependencies\n",
"import numpy as np\n",
"from scipy.stats import unitary_group\n",
"from unitary_decomp.fourier_interferometer import compact_fourier_decomposition, circuit_reconstruction\n",
"from udecomp.fourier_interferometer import compact_fourier_decomposition, circuit_reconstruction\n",
"np.set_printoptions(precision=3, suppress=True, linewidth=150)"
]
},
Expand Down Expand Up @@ -209,14 +209,14 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": null,
"id": "179234a9",
"metadata": {},
"outputs": [],
"source": [
"# Import the plotting function\n",
"import matplotlib.pyplot as plt\n",
"from unitary_decomp.plot.phases_plot import plot_phases"
"from udecomp.plot.phases_plot import plot_phases"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions examples/lplm_example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
},
{
"cell_type": "code",
"execution_count": 11,
"execution_count": null,
"id": "7f574ccd",
"metadata": {},
"outputs": [],
"source": [
"# Import dependencies\n",
"from unitary_decomp import lplm_interferometer as li\n",
"from udecomp import lplm_interferometer as li\n",
"\n",
"import numpy as np\n",
"from scipy.stats import unitary_group"
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "unitary_decomp"
name = "udecomp"
dynamic = ["version"]
description = "Decompositions and approximations of linear optical unitaries."
authors = [
Expand Down Expand Up @@ -35,4 +35,4 @@ Homepage = "https://github.com/polyquantique/Unitary-Decomp"
where = ["src"]

[tool.setuptools.dynamic]
version = {attr = "unitary_decomp.__version__"}
version = {attr = "udecomp.__version__"}
21 changes: 9 additions & 12 deletions src/unitary_decomp/__init__.py → src/udecomp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""# Unitary Decompositions
"""# UDecomp

This package provides functions to decompose and approximate linear optical transformations into various interferometer configurations.

Expand All @@ -31,14 +31,11 @@
`Unitary-Decomp` also includes optimization routines in the `optimization` subpackage to find approximated decompositions using gradient-based methods.
"""

__version__ = "0.1.0"

from unitary_decomp.bell_interferometer import bell_decomposition
from unitary_decomp.clements_interferometer import clements_decomposition, mzi_decomposition
from unitary_decomp.fourier_interferometer import (
compact_fourier_decomposition,
fourier_decomposition,
)
from unitary_decomp.lplm_interferometer import lplm_decomposition
from unitary_decomp.optimization.fourier_optimizer import mask_optimizer
from unitary_decomp.optimization.jax_optimizer import jax_mask_optimizer
__version__ = "1.0.0"

from udecomp.bell_interferometer import bell_decomposition
from udecomp.clements_interferometer import clements_decomposition, mzi_decomposition
from udecomp.fourier_interferometer import compact_fourier_decomposition, fourier_decomposition
from udecomp.lplm_interferometer import lplm_decomposition
from udecomp.optimization.fourier_optimizer import mask_optimizer
from udecomp.optimization.jax_optimizer import jax_mask_optimizer
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
- `jax_optimizer`: Uses the `Jax` and `Optax` libraries to find the phase masks that minimize the infidelity with a target unitary efficiently.
"""

from unitary_decomp.optimization.fourier_optimizer import mask_optimizer
from unitary_decomp.optimization.jax_optimizer import jax_mask_optimizer, scipy_mask_optimizer
from udecomp.optimization.fourier_optimizer import mask_optimizer
from udecomp.optimization.jax_optimizer import jax_mask_optimizer, scipy_mask_optimizer
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
from numpy.typing import NDArray
from scipy.optimize import basinhopping

from unitary_decomp import matrix_operations as mo
from unitary_decomp.fourier_interferometer import FourierDecomp
from udecomp import matrix_operations as mo
from udecomp.fourier_interferometer import FourierDecomp


def fidelity(U: NDArray, V: NDArray) -> float:
Expand Down Expand Up @@ -142,8 +142,8 @@ def mask_optimizer(
Example:
>>> import numpy as np
>>> from scipy.stats import unitary_group
>>> from unitary_decomp.fourier_interferometer import circuit_reconstruction
>>> from unitary_decomp.optimization import mask_optimizer
>>> from udecomp.fourier_interferometer import circuit_reconstruction
>>> from udecomp.optimization import mask_optimizer

>>> U = unitary_group(dim=6, seed=137).rvs() # Generate a random 6x6 unitary matrix
>>> mask_shape = np.array([True, True, True, True, True, False]) # Define the shape of the phase masks with no phase shifter on the last mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from jax.scipy.optimize import minimize
from scipy.linalg import dft

from unitary_decomp.fourier_interferometer import FourierDecomp
from udecomp.fourier_interferometer import FourierDecomp

# Enable 64-bit precision for JAX operations
jax.config.update("jax_enable_x64", True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
- `clements_plot`: Module for the characterization of the Clements decomposition.
"""

from unitary_decomp.plot.phases_plot import plot_phases
from udecomp.plot.phases_plot import plot_phases
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import pandas as pd
from scipy.stats import linregress, unitary_group

from unitary_decomp.clements_interferometer import circuit_reconstruction, clements_decomposition
from udecomp.clements_interferometer import circuit_reconstruction, clements_decomposition


def fidelity(V: np.ndarray, U: np.ndarray) -> float:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

>>> import matplotlib.pyplot as plt
>>> from scipy.stats import unitary_group
>>> from unitary_decomp.plot.phases_plot import plot_phases
>>> from unitary_decomp import compact_fourier_decomposition
>>> from udecomp.plot.phases_plot import plot_phases
>>> from udecomp import compact_fourier_decomposition

>>> # Generate a random unitary matrix
>>> U = unitary_group(10, seed=42).rvs()
Expand All @@ -48,8 +48,8 @@
import matplotlib.pyplot as plt
import numpy as np

from unitary_decomp.fourier_interferometer import FourierDecomp
from unitary_decomp.lplm_interferometer import LplmDecomp
from udecomp.fourier_interferometer import FourierDecomp
from udecomp.lplm_interferometer import LplmDecomp


def _generate_phase_matrix(decomposition: FourierDecomp | LplmDecomp) -> np.ndarray:
Expand Down Expand Up @@ -80,8 +80,8 @@ def plot_phases(

Args:
decomposition (FourierDecomp | LplmDecomp): The decomposition object containing the mask sequence. Can be obtained from
`unitary_decomp.fourier_interferometer.compact_fourier_decomposition` or
`unitary_decomp.lplm_interferometer.lplm_decomposition`.
`udecomp.fourier_interferometer.compact_fourier_decomposition` or
`udecomp.lplm_interferometer.lplm_decomposition`.

ax (plt.Axes, optional): The matplotlib Axes object to plot on. If None, a new figure and axes will be created.

Expand Down
2 changes: 1 addition & 1 deletion tests/test_bell_interferometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from scipy.linalg import dft
from scipy.stats import unitary_group

from unitary_decomp import bell_interferometer as bi
from udecomp import bell_interferometer as bi

"""Unit tests for the Bell Interferometer module."""

Expand Down
2 changes: 1 addition & 1 deletion tests/test_clements_interferometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from scipy.fft import fft
from scipy.stats import unitary_group

from unitary_decomp import clements_interferometer as ci
from udecomp import clements_interferometer as ci

"""Unit tests for the Clements interferometer module."""

Expand Down
4 changes: 2 additions & 2 deletions tests/test_fourier_interferometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from scipy.linalg import dft
from scipy.stats import unitary_group

import unitary_decomp.fourier_interferometer as fi
from unitary_decomp import matrix_operations as mo
import udecomp.fourier_interferometer as fi
from udecomp import matrix_operations as mo

"""Unit tests for the Fourier Interferometer module."""

Expand Down
6 changes: 3 additions & 3 deletions tests/test_fourier_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import pytest
from scipy.stats import unitary_group

from unitary_decomp.fourier_interferometer import circuit_reconstruction
from unitary_decomp.matrix_operations import matrix_interleave
from unitary_decomp.optimization.fourier_optimizer import fidelity, mask_optimizer
from udecomp.fourier_interferometer import circuit_reconstruction
from udecomp.matrix_operations import matrix_interleave
from udecomp.optimization.fourier_optimizer import fidelity, mask_optimizer

"""Unit tests for the `fourier_optimizer` module."""

Expand Down
4 changes: 2 additions & 2 deletions tests/test_jax_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from scipy.linalg import dft
from scipy.stats import unitary_group

import unitary_decomp.optimization.jax_optimizer as jax_opt
from unitary_decomp.fourier_interferometer import FourierDecomp, circuit_reconstruction
import udecomp.optimization.jax_optimizer as jax_opt
from udecomp.fourier_interferometer import FourierDecomp, circuit_reconstruction

np.random.seed(42)

Expand Down
2 changes: 1 addition & 1 deletion tests/test_lplm_interferometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from scipy.linalg import dft
from scipy.stats import unitary_group

import unitary_decomp.lplm_interferometer as li
import udecomp.lplm_interferometer as li

np.random.seed(42)

Expand Down
2 changes: 1 addition & 1 deletion tests/test_matrix_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from scipy.linalg import dft
from scipy.stats import unitary_group

from unitary_decomp import matrix_operations as mo
from udecomp import matrix_operations as mo

"""Unit tests for the matrix operations module."""

Expand Down