Implementation of Dykstra's algorithm for projecting a point onto the intersection of multiple convex sets (half-spaces) in Hilbert space. This project includes implementations of the standard algorithm, a hybrid MAP-Dykstra variant, and a modified version with stalling detection and fast-forwarding.
Dykstra's algorithm is a cyclic projection method used to find the projection of a point onto a feasible region defined by the intersection of multiple convex sets.
- Standard Dykstra's Algorithm - Classic cyclic projection implementation
- MAP-Dykstra Hybrid - Combines Method of Alternating Projections with Dykstra for improved performance
- Stalling Detection - Detects and prevents algorithmic stalling (when the algorithm gets stuck cycling)
- Interactive Visualisation - 2D visualisation of projection paths, half-spaces, and convergence
- Error Tracking - Monitors convergence and distance to optimal solution
- Rounded Box Support - Edge-rounding utilities for non-axis-aligned convex regions
- Generalised Implementation - Works for any number of dimensions and half-spaces
Navigate to the working version and run the main example:
cd Python/Working\ Version
python main.pyThis will project a point onto the intersection of a box and a line, displaying:
- The original point being projected
- The final projection result
- The iteration history and convergence behavior
- Active and inactive half-spaces
- A visual representation of the 2D feasible region
- LaTeX directory - Up-to-date mathematical report and derivations:
/Latex/Current Version - Python directory - Production code:
/Python/Working Version
Install required dependencies:
pip install -r requirements.txtThe main script projects a point to the intersection of a box and a line:
# In Python/Working Version/main.py
z = np.array([-4., 1.4]) # Point to project
# Box constraints: -1 <= x <= 1, -1 <= y <= 1
# Line constraint: x/2 + y = 1Run with:
python main.pyUncomment the desired test case in main.py to test various scenarios:
- Simple top left (with stalling) - Tests stalling detection capability
- Simple top left (no stalling) - Basic example without stalling issues
- Point in intersection - Tests handling of points already in the feasible region
- Very far points - Tests convergence from distant starting points in all directions
- Various corners - Tests algorithm from all corners/directions
Each case has a corresponding starting point z, plot range, and configuration.
Three solver variants are available in main.py:
# Standard Dykstra's Algorithm
solver = DykstraProjectionSolver(
z, A, c, max_iter,
track_error=True,
plot_errors=False,
plot_active_halfspaces=True,
delete_spaces=True
)
# Hybrid MAP-Dykstra (often faster)
solver = DykstraMapHybridSolver(
z, A, c, max_iter,
track_error=True,
plot_errors=False,
plot_active_halfspaces=True,
delete_spaces=True
)
# Dykstra with Stalling Detection
solver = DykstraStallDetectionSolver(
z, A, c, max_iter,
track_error=True,
plot_errors=False,
plot_active_halfspaces=True,
delete_spaces=True
)
result = solver.solve()
projection_point = result.projectionFor non-rectangular convex regions, use edge rounding:
from edge_rounder import rounded_box_constraints
center = (0, 0)
width = 2
height = 2
corner_count = 3 # Number of corners to round
N_box, c_box = rounded_box_constraints(center, width, height, corner_count)Define arbitrary convex constraints:
import numpy as np
# Define half-spaces: N*x <= c
# Example: Create 4 constraints forming a box
N = np.array([
[1., 0.], # x <= 1
[-1., 0.], # x >= -1
[0., 1.], # y <= 1
[0., -1.] # y >= -1
])
c = np.array([1., 1., 1., 1.])
# Add more constraints (e.g., a line)
N_line = np.array([[1/2, 1], [-1/2, -1]])
c_line = np.array([1, -1])
# Combine all constraints
A = np.vstack([N, N_line])
c_full = np.hstack([c, c_line])
# Create and solve
solver = DykstraProjectionSolver(z, A, c_full, max_iter=50)
result = solver.solve()Generate a comparison figure showing two different solver variants side-by-side:
python paper_figure.pyThis script:
- Runs two solvers on the same problem:
- Dykstra - Standard Dykstra's algorithm
- Fast Forward - Dykstra with stalling detection
- Exports results to CSV files in
./results/ - Displays a three-panel comparison figure with:
- Top Panel - Projection visualisation for one solver
- Middle Panel - Error convergence comparison with stalling highlighted
- Bottom Panel - Halfspace activity comparison
The visualisation can be customised:
from visualiser import ComparisonVisualiser
visualiser = ComparisonVisualiser(
result1, result2, nc_pairs1, nc_pairs2,
max_iter, x_range, y_range,
solver1_name, solver2_name,
z,
display_result_index=0, # Show first solver's projection (0 or 1)
display_halfspace_index=0 # Show first halfspace activity (0, 1, 2, ...)
)
visualiser.visualise()Main solver implementations:
ConvexProjectionSolver- Base abstract classDykstraProjectionSolver- Standard Dykstra's cyclic projection algorithmDykstraMapHybridSolver- Hybrid Method of Alternating Projections with DykstraDykstraStallDetectionSolver- Stalling-aware variant with early termination
Comprehensive visualisation system for projection results:
- Visualiser - Horizontal layout for results
- VerticalVisualiser - Vertical layout for results
- ComparisonVisualiser - Side-by-side comparison of two solver runs with:
- Individual projection visualisation
- Error convergence comparison with stalling detection
- Halfspace activity tracking
- ResultExporter - CSV export/import for solver results with full data serialisation
Displays:
- Half-space constraints and their boundaries
- Complete projection paths through iterations
- Active vs. inactive constraints
- Error evolution and convergence metrics
- Quiver plots for gradient information
- Stalling periods highlighted in error convergence plots
Gradient and optimisation utilities:
- Quadratic programming solver
Utilities for rounding box corners:
rounded_box_constraints()- Create smoothed box regions
Data structure storing solver outputs:
- Final projection point
- Complete iteration history
- Convergence metrics and error tracking
- Active half-space indices at each iteration
- Distance to optimal solution
| README.md (Project documentation)
| requirements.txt (Python dependencies)
|
+---Application
| \---Final Drafts (Project deliverables and applications)
|
+---Books & Articles (Research papers and references)
| +---Baushke (Baushke research materials)
| +---claudio_projection (Personal research and notes)
| \---Notes (Reference lecture notes)
| C21_MPC_Lecture_Notes.pdf
| C21_MPC_Problems.pdf
| dykstra.pdf
| Dykstra's Projection Algorithm.pdf
| LQR + Riccati.pdf
| MPC derivation of condensed form.pdf
|
+---Latex
| +---Current Version (Main paper and report)
| | | paper.tex (Main research paper)
| | | master_bib_abbrev.bib (Bibliography)
| | | mymath.sty (Custom LaTeX math macros)
| | |
| | +---Figures (Generated plots and visualisations)
| | |
| | +---Packages
| | | \---packages.tex (LaTeX package configurations)
| | |
| | \---Sections (Main paper sections)
| | 1-Introduction.tex
| | 2-Dykstra Background.tex
| | 3-Main Results.tex
| | 4-Conclusion.tex
| | Fast Forwarding Stalling Period.tex
| | The Polyhedral Case.tex
| |
| +---Idris Version (Functional programming implementation)
| \---Initial Version (Early version iterations)
|
\---Python
+---Previous Versions (Development history)
| | (Versions 1-9 showing algorithm evolution)
| |
| +---Version 1 (Initial implementation)
| +---Version 2 (Added plotting)
| +---Version 3 (Path visualisation)
| +---Version 4 (Added gradients)
| +---Version 5-9 (Iterative improvements)
|
\---Working Version (β CURRENT PRODUCTION CODE)
main.py (π Entry point - run this to test)
paper_figure.py (π Generate comparison figure from paper)
convex_projection_solver.py (Core solver implementations)
visualiser.py (2D visualisation engine + result export)
projection_result.py (Result data structure)
gradient.py (Gradient/optimisation utilities)
edge_rounder.py (Box rounding utilities)
dykstra.py (Algorithm helper functions)The algorithm iteratively projects onto each constraint in a cyclic manner:
- For each half-space constraint in sequence
- Project the current point onto that constraint boundary
- Store the projection offset
- Repeat until convergence or iteration limit
Dykstra's algorithm can "stall" when it gets trapped cycling between adjacent constraints without converging. This project includes detection and prevention mechanisms.
The stalling-aware variant detects when cycling occurs and employs strategies to escape, improving convergence in difficult cases.
- Dimension Independence - Works for any dimension (though visualisation limited to 2D)
- Scalability - Performance depends on number of constraints and dimensionality
- Convergence - Guaranteed to converge for convex constraint sets
- Stalling - Modified version handles degenerate cases better
Research papers and academic references are stored in /Books & Articles. Key topics covered:
- Convergence analysis of Dykstra's algorithm
- Stalling phenomena in cyclic projection methods
- Method of Alternating Projections (MAP)
- Model Predictive Control applications
- Proximal splitting methods
Claudio Vestini - University of Oxford
Project funded by Keble Research Grant KSRG118 "