Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e887cca
feat: WIP proximal module
mrava87SW Jun 14, 2026
668ba69
feat: added proximal optimization module
mrava87SW Jun 15, 2026
fd3fc3b
feat: improvements to ProxOperator
mrava87SW Jun 15, 2026
fa1badf
feat: enabled TV-reg with ADMML2
mrava87SW Jun 18, 2026
9da4161
test: added tests for nested StackedDistributedArray
mrava87SW Jun 18, 2026
f23cef5
Merge branch 'PyLops:main' into feat-prox
mrava87 Jun 19, 2026
3b45e9a
doc: fix figure numbering in poststack tutorial
mrava87SW Jun 22, 2026
02aa9c1
Merge branch 'feat-prox' of https://github.com/mrava87/pylops-mpi int…
mrava87SW Jun 22, 2026
6096027
test: added test_prox
mrava87SW Jun 23, 2026
70eb6c0
build: added pyproximal to dependencies
mrava87SW Jun 23, 2026
74e8e35
feat: align DistributedArray with main branch
mrava87SW Jul 5, 2026
f9d3393
feat: align test_distributedarray with main beanch
mrava87SW Jul 5, 2026
5a55c19
doc: improved example and tests for prox
mrava87SW Jul 5, 2026
cb86beb
Merge branch 'main' into feat-prox
mrava87 Jul 5, 2026
e61ece9
fix: extract item from f
mrava87SW Jul 5, 2026
62353b5
minor: fix flake8
mrava87SW Jul 5, 2026
b151dc8
feat: add error for L2 with broadcast
mrava87SW Jul 13, 2026
301a637
feat: more on skipping broadcast
mrava87SW Jul 13, 2026
48c444c
doc: finalized plot_prox
mrava87SW Jul 13, 2026
a043afc
fix: changed output of MPIProxOperator.__call__ to be scalar
mrava87SW Jul 13, 2026
bd48551
doc: added TV inversion to poststack_cupy
mrava87SW Jul 13, 2026
417d864
minor: fix flake8
mrava87SW Jul 13, 2026
7826d50
fix: revert change
mrava87SW Jul 13, 2026
f78e01e
minor: removed backtracking from ProximalGradient
mrava87SW Jul 13, 2026
7eafb19
minor: reverted raises on broadcast in L2
mrava87SW Jul 13, 2026
e4344a1
doc: added proximal methods to doc
mrava87SW Jul 13, 2026
7ef61ec
minor: fix flake8
mrava87SW Jul 13, 2026
0cdcf6d
fix: removed test for L2 broadcast
mrava87SW Jul 13, 2026
195929c
feat: added support for broadcast partition in MPIL2
mrava87SW Jul 14, 2026
ab0dda0
doc: added example with proximal solvers
mrava87SW Jul 14, 2026
6c475d1
doc: finalized proxsolver example
mrava87SW Jul 14, 2026
2fb4560
minor: fix flake8
mrava87SW Jul 14, 2026
5a50a4b
doc: added docstrings to proximal solvers
mrava87SW Jul 14, 2026
6a152b0
minor: fix flake8
mrava87SW Jul 14, 2026
40bcf3e
feat: force __call__ output out of GPU
mrava87SW Jul 17, 2026
fa78c63
test: added tests for ProximalGradient
mrava87SW Jul 20, 2026
5751995
fix: force outputs of call to be always numpy
mrava87SW Jul 20, 2026
b5a6724
doc: more examples of proximal in tutorials
mrava87SW Jul 20, 2026
02e4a5b
test: more tests for proximal
mrava87SW Jul 20, 2026
8ee5c26
Update prox __call__ to check for scalar
rohanbabbar04 Jul 26, 2026
df2a936
Minor change in rtol
rohanbabbar04 Jul 26, 2026
c0eaff0
Update github action testing
rohanbabbar04 Jul 26, 2026
62de62a
Remove rank = 8 from GA
rohanbabbar04 Jul 26, 2026
be0fd5c
Remove rank = 8 from GA, update command-mpiexec
rohanbabbar04 Jul 26, 2026
1de7bba
Change fail-fast: false
rohanbabbar04 Jul 26, 2026
475e024
Add rank=8
rohanbabbar04 Jul 26, 2026
ab65c4a
Remove rank=8
rohanbabbar04 Jul 27, 2026
817712d
Update mpiexec commands to before
rohanbabbar04 Jul 27, 2026
0fe26e4
minor: fix servedoc target
mrava87SW Jul 29, 2026
098dbf7
minor: fix flake8
mrava87SW Jul 29, 2026
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
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ on:
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ['3.11', '3.12', '3.13', '3.14']
mpi: ['mpich', 'openmpi', 'intelmpi']
rank: ['2', '4', '8']
rank: ['2', '4']
exclude:
- os: macos-latest
mpi: 'intelmpi'
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,22 @@ doc:
doc_cupy:
cp tutorials_cupy/* tutorials/
cd docs && rm -rf source/api/generated && rm -rf source/gallery &&\
rm -rf source/tutorials && rm -rf source/tutorials && rm -rf build &&\
cd .. && sphinx-build -b html docs/source docs/build
rm -rf source/tutorials && rm -rf build &&\
cd .. && sphinx-build -b html docs/source docs/build &&\
rm tutorials/*_cupy.py

doc_nccl:
cp tutorials_cupy/* tutorials_nccl/* tutorials/
cd docs && rm -rf source/api/generated && rm -rf source/gallery &&\
rm -rf source/tutorials && rm -rf source/tutorials && rm -rf build &&\
cd .. && sphinx-build -b html docs/source docs/build
rm -rf source/tutorials && rm -rf build &&\
cd .. && sphinx-build -b html docs/source docs/build &&\
rm tutorials/*_cupy.py tutorials/*_nccl.py

docupdate:
cd docs && NCCL_PYLOPS_MPI=0 make html && cd ..

servedoc:
$(PYTHON) -m http.server --directory docs/build/
$(PYTHON) -m http.server --directory docs/build/html/

# Run examples using mpi
run_examples:
Expand Down
38 changes: 37 additions & 1 deletion docs/source/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ Basic Operators
MPIStackedVStack
MPIHStack
MPIHalo


Derivatives
~~~~~~~~~~~
Expand Down Expand Up @@ -88,6 +87,30 @@ Wave-Equation processing
MPIMDC


Proximal operators
------------------

Templates
~~~~~~~~~

.. currentmodule:: pylops_mpi.proximal

.. autosummary::
:toctree: generated/

MPIProxOperator

Basic Operators
~~~~~~~~~~~~~~~

.. currentmodule:: pylops_mpi.proximal.proximal

.. autosummary::
:toctree: generated/

MPIL2


Solvers
-------

Expand Down Expand Up @@ -129,6 +152,19 @@ Sparsity
ista
fista


Proximal
~~~~~~~~

.. currentmodule:: pylops_mpi.proximal.optimization.primal

.. autosummary::
:toctree: generated/

ProximalGradient
ADMML2


Utils
-----

Expand Down
1 change: 1 addition & 0 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The minimal set of dependencies for the PyLops-MPI project is:
* `Matplotlib <https://matplotlib.org/>`_
* `MPI4py <https://mpi4py.readthedocs.io/en/stable/>`_
* `PyLops <https://pylops.readthedocs.io/en/stable/>`_
* `PyProximal <https://pyproximal.readthedocs.io/en/stable/>`_

Additionally, to use the CUDA-aware MPI engine, the following additional
dependencies are required:
Expand Down
1 change: 1 addition & 0 deletions environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies:
- scipy>=1.8.0
- mpi4py
- pylops>=2.0.0
- pyproximal
- matplotlib
- ipython
- pytest
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ dependencies:
- numpy>=1.15.0
- scipy>=1.8.0
- pylops>=2.0.0
- pyproximal
- matplotlib
- mpi4py
176 changes: 176 additions & 0 deletions examples/plot_prox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
r"""
Proximal operators
==================

This example demonstrates the use of the :py:module:`pylops_mpi.proximal`
module, and more specifically how to create and apply PyProximal operators
to distributed array.

"""
import numpy as np
from mpi4py import MPI
from matplotlib import pyplot as plt

import pylops
import pyproximal

import pylops_mpi

np.random.seed(42)
plt.close("all")
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

###############################################################################
# Let's start with so-called separable proximal operators. These are functionals
# whose proximal operator can be computed in a element-wise fashion. As such,
# no special implementation is required for the distributed counterpart of
# those operators. Instead, we can simply wrap the PyProximal operator into
# a :py:class:`pylops_mpi.proximal.MPIProxOperator`.
#
# We take the :py:class:`pyproximal.proximal.L1` norm as an example.

n = 10
arr = pylops_mpi.DistributedArray(global_shape=n * size,
partition=pylops_mpi.Partition.SCATTER)
arr[:] = rank * np.arange(n)

l1 = pyproximal.proximal.L1(sigma=2.0)
l1d = pylops_mpi.proximal.MPIProxOperator(l1)

# Call
f = l1d(arr)

# Proximal
prox = l1d.prox(arr, .1)
proxdlocal = prox.asarray()

dprox = l1d.proxdual(arr, .1)
dproxdlocal = dprox.asarray()

arrlocal = arr.asarray()
if rank == 0:
flocal = l1(arrlocal)
proxlocal = l1.prox(arrlocal, .1)
dproxlocal = l1.proxdual(arrlocal, .1)
print("||x||_1: ", f, flocal)
print("prox_||x||_1: ", all(proxdlocal == proxlocal))
print("proxd_||x||_1: ", all(dproxdlocal == dproxlocal))

###############################################################################
# We repeat now the same with the :py:class:`pyproximal.proximal.Box` operator.

arr = pylops_mpi.DistributedArray(global_shape=n * size,
partition=pylops_mpi.Partition.SCATTER)

arr[:] = 3 * np.ones(n)
if rank == 0:
arr[n//2] = 20 # outside of the box

box = pyproximal.Box(lower=1., upper=5.)
boxd = pylops_mpi.proximal.MPIProxOperator(box)

# Call
f = boxd(arr)

# Proximal
prox = boxd.prox(arr, .1)
proxdlocal = prox.asarray()

# Dual-Proximal
dprox = boxd.proxdual(arr, .1)
dproxdlocal = dprox.asarray()

arrlocal = arr.asarray()
if rank == 0:
flocal = box(arrlocal)
proxlocal = box.prox(arrlocal, .1)
dproxlocal = box.proxdual(arrlocal, .1)
print("Box(x): ", f, flocal)
print("prox_Box ", all(proxdlocal == proxlocal))
print("proxd_Box ", all(dproxdlocal == dproxlocal))

###############################################################################
# We move on now to a operator that is not separable and must be fully
# re-implemented in a distributed fashion, namely the
# :py:class:`pylops_mpi.proximal.MPIL2` norm.
#
# More precisely, when ``Op`` and ``b`` are passed to this operator,
# its proximal does call for the solution of a distributed inverse problem.
#
# However, let's start with the simplest case: :math:`||\mathbf{x}||_2^2`

arr = pylops_mpi.DistributedArray(global_shape=n * size,
partition=pylops_mpi.Partition.SCATTER)

arr[:] = rank * np.arange(n)

l2 = pyproximal.L2(sigma=2.0)
l2d = pylops_mpi.proximal.MPIL2(sigma=2.0)

# Call
f = l2d(arr)

# Proximal
prox = l2d.prox(arr, .1)
proxdlocal = prox.asarray()

# Gradient
grad = l2d.grad(arr)
graddlocal = grad.asarray()

arrlocal = arr.asarray()
if rank == 0:
flocal = l2(arrlocal)
proxlocal = l2.prox(arrlocal, .1)
gradlocal = l2.grad(arrlocal)
print("||x||_2^2: ", f, flocal)
print("prox_||x||_2^2: ", all(proxdlocal == proxlocal))
print("grad_||x||_2^2: ", all(graddlocal == gradlocal))

###############################################################################
# Next we move onto the more general case
# :math:`||\mathbf{Op} \mathbf{x} - \mathbf{b}||_2^2`

solver="cgls"
Op = pylops.Diagonal(np.ones(n * size))
Opd = pylops_mpi.MPIBlockDiag([pylops.Diagonal(np.ones(n)),])

b = pylops_mpi.DistributedArray(global_shape=n * size,
partition=pylops_mpi.Partition.SCATTER)
b[:] = rank * np.ones(n)
blocal = b.asarray()

x0 = arr.zeros_like()
x0local = x0.asarray()

l2 = pyproximal.L2(
Op=Op, b=blocal, sigma=2.0,
solver=solver, x0=x0local,
kwargs_solver=dict(show=True))
l2d = pylops_mpi.proximal.MPIL2(
Op=Opd, b=b, sigma=2.0,
solver=solver, x0=x0,
kwargs_solver=dict(show=True if rank==0 else False))

# Call
f = l2d(arr)

# Proximal
prox = l2d.prox(arr, .1)
proxdlocal = prox.asarray()

# Gradient
grad = l2d.grad(arr)
graddlocal = grad.asarray()

arrlocal = arr.asarray()
if rank == 0:
flocal = l2(arrlocal)
proxlocal = l2.prox(arrlocal, .1)
gradlocal = l2.grad(arrlocal)
print("||Op . x - b||_2^2: ", f, flocal)
print("prox_||Op . x - b||_2^2 - norm diff=",
np.linalg.norm(proxdlocal - proxlocal))
print("grad_||Op . x - b||_2^2: ", all(graddlocal == gradlocal))
Loading
Loading