A comprehensive C++ implementation and performance analysis of advanced linear system solving methods with sparse matrix support, iterative solvers, and preconditioners.
| Feature | Implementation | Performance Highlight |
|---|---|---|
| Direct Solvers | Gaussian Elimination, LU, Cholesky | Machine precision (10โปยนยฒ) |
| Iterative Solvers | Gauss-Seidel, Jacobi, SOR, CG | 50ร faster on large matrices |
| Sparse Matrices | CSR format | 99.7% memory reduction |
| Preconditioners | Jacobi (diagonal) | Faster convergence |
| Matrix Analysis | Condition number, norms, properties | Stability insights |
| Memory Profiling | Peak usage tracking | Resource optimization |
| Exception Handling | Custom hierarchy with suggestions | Better debugging |
| Unit Tests | Google Test framework | 100% pass rate |
NEW! Python GUI with real-time C++ solver integration:
# Install dependencies
pip install -r requirements.txt
# Launch GUI
python3 gui.pyFeatures:
- โจ Matrix Input Grid - Easy matrix and vector entry
- ๐๏ธ Solver Selection - Choose from 4 different algorithms
- ๐ Real-time Visualization - Matrix heatmap & solution graphs
- โก C++ Backend - Uses actual C++ solvers (not simulation)
- ๐ Performance Metrics - Execution time & residual error
- ๐จ Preset Matrices - Identity, Random, Diagonal dominant
This project implements and benchmarks different algorithms for solving systems of linear equations Ax = b, comparing their:
- Execution time across different matrix sizes
- Accuracy (solution error)
- Scalability with increasing problem size
| Algorithm | Complexity | Best Use Case | Advantages |
|---|---|---|---|
| Gaussian Elimination | O(nยณ) | Small-medium matrices | Partial pivoting, stable |
| LU Factorization | O(nยณ) | Multiple right-hand sides | Reusable decomposition |
| Cholesky | O(nยณ/6) | SPD matrices | 2ร faster than LU |
| Algorithm | Complexity | Best Use Case | Convergence |
|---|---|---|---|
| Gauss-Seidel | O(knยฒ) | Large dense matrices | Faster than Jacobi |
| Jacobi | O(knยฒ) | Parallel computing | All updates independent |
| SOR | O(knยฒ) | Diagonal dominant | 20-30% faster than GS |
| Conjugate Gradient | O(kn) | Sparse SPD matrices | Ultra-fast for sparse |
- Sparse Matrices: CSR (Compressed Sparse Row) format for 99%+ memory savings
- Preconditioners: Jacobi preconditioner for improved convergence
- Matrix Analysis: Condition number, matrix norms, diagonal dominance checking
- Memory Profiling: Track peak memory usage and compare dense vs sparse
- Exception Handling: Detailed error messages with troubleshooting suggestions
optimization-and-search-cpp/
โโโ src/
โ โโโ linear_solvers/
โ โ โโโ gaussian_elimination.{h,cpp} # Gaussian elimination with pivoting
โ โ โโโ lu_factorization.{h,cpp} # LU decomposition
โ โ โโโ iterative_solver.{h,cpp} # Gauss-Seidel & Jacobi
โ โ โโโ sparse_iterative_solver.{h,cpp} # Conjugate Gradient for sparse
โ โ โโโ advanced_solvers.{h,cpp} # SOR & Cholesky
โ โ โโโ preconditioner.{h,cpp} # Jacobi preconditioner
โ โโโ utils/
โ โ โโโ matrix.{h,cpp} # Dense matrix operations
โ โ โโโ sparse_matrix.{h,cpp} # CSR sparse matrix
โ โ โโโ matrix_analysis.{h,cpp} # Condition number, norms
โ โ โโโ memory_profiler.{h,cpp} # Memory usage tracking
โ โ โโโ timer.{h,cpp} # Performance timing
โ โ โโโ exceptions.h # Custom exception hierarchy
โ โโโ main.cpp # Main benchmark driver
โ โโโ advanced_demo.cpp # Advanced features demo
โโโ tests/
โ โโโ test_gaussian.cpp # Unit tests for direct solvers
โ โโโ test_sparse.cpp # Unit tests for sparse matrices
โ โโโ test_advanced.cpp # Unit tests for SOR/Cholesky
โ โโโ CMakeLists.txt # Test configuration
โโโ CMakeLists.txt # Main build configuration
โโโ Makefile # Alternative build system
โโโ visualize.py # Python visualization script
โโโ benchmark_results.csv # Generated benchmark data
โโโ plots/ # Generated performance graphs
โโโ README.md
- C++17 compatible compiler (GCC 7+, Clang 5+, MSVC 2017+)
- CMake 3.10+
- Google Test (for unit tests)
- Python 3.7+ (for visualization)
- Python packages:
pandas,matplotlib,seaborn
# Clone the repository
git clone https://github.com/Talha-Dmr/optimization-and-search-cpp.git
cd optimization-and-search-cpp
# Create build directory and compile
mkdir -p build
cd build
cmake ..
make
# Run the benchmark
./linear_solvers
# Run unit tests (optional)
ctest --output-on-failure# Build all targets
make
# Run advanced features demo
make demo
# Run main benchmark
make run
# Clean build artifacts
make clean
# Show available targets
make help# Install Python dependencies (if needed)
pip install pandas matplotlib seaborn
# Generate plots and analysis
python3 visualize.pyThis will create:
benchmark_results.csv- Raw benchmark dataplots/directory with performance graphsplots/summary_report.txt- Text summary of results
# Using Makefile
make demo
# Or directly
./build/advanced_demoThe demo showcases:
- Sparse matrix operations with CSR format
- Matrix analysis (condition number, norms)
- Memory profiling and comparison
- Performance benchmarks
The program tests matrices of sizes: 10ร10, 50ร50, 100ร100, 200ร200, 500ร500, 1000ร1000
- Small matrices (โค100): Direct methods are faster
- Large matrices (โฅ500): Iterative methods are ~10x faster
- Gauss-Seidel generally outperforms Jacobi in convergence speed
- Direct methods: Error ~10โปยนยฒ to 10โปยนโด (machine precision)
- Iterative methods: Error ~10โปโธ (sufficient for most applications)
- All methods successfully solve the test systems
- Direct methods: Time grows as O(nยณ) - becomes slow for large n
- Iterative methods: Better scaling for large sparse matrices
- Performance gap increases dramatically with matrix size
| Method | Time (ms) | Error | Speedup |
|---|---|---|---|
| Gaussian Elimination | 843 | 3.8ร10โปยนยน | 1ร |
| LU Factorization | 1094 | 1.4ร10โปยนยน | 0.77ร |
| Gauss-Seidel | 17 | 1.1ร10โปโธ | 50ร |
| Jacobi | 20 | 2.1ร10โปโน | 42ร |
| Metric | Sparse (CSR) | Dense | Advantage |
|---|---|---|---|
| Memory | 54.66 KB | 7.65 MB | 99.3% savings |
| Storage | 2,998 elements | 1,000,000 elements | 99.7% reduction |
| Solve Time (CG) | 0.08 ms | N/A | Ultra-fast |
| Sparsity | 99.70% | 0% | Highly sparse |
Actual benchmark results - Hardware may vary
The visualize.py script generates:
time_comparison_diagonal.png- Execution time vs matrix size (log-log plot)time_comparison_random.png- Direct methods on random matriceserror_comparison.png- Solution accuracy comparisonspeedup_comparison.png- Iterative methods speedup vs direct methodsbar_comparison.png- Bar charts for selected matrix sizessummary_report.txt- Detailed statistical analysis
- Elements uniformly distributed in [1, 10]
- Tests general case performance
- Used for direct methods comparison
- Ensures convergence for iterative methods
- More representative of real-world sparse systems
- Condition: |a_ii| > ฮฃ|a_ij| for all rows
| Scenario | Recommended Method | Reason |
|---|---|---|
| Small matrices (n < 100) | Gaussian Elimination | Simple, fast, accurate |
| Multiple systems with same A | LU Factorization | Reuse decomposition |
| Large sparse matrices | Sparse CG | 99% memory savings, ultra-fast |
| Large dense matrices | Gauss-Seidel | 50ร faster than direct |
| Parallel computing | Jacobi | Independent updates |
| High precision required | Direct methods | Machine precision (10โปยนยฒ) |
| Real-time applications | Iterative methods | Speed vs accuracy tradeoff |
| Memory-constrained | Sparse matrices | 100ร less memory |
| Tridiagonal systems | Sparse CG | Optimal performance |
Matrix size?
โโ n < 100
โ โโ Use Gaussian Elimination (fast enough, accurate)
โ
โโ 100 โค n < 500
โ โโ Sparse? โ Use Sparse Iterative (CG/Gauss-Seidel)
โ โโ Dense? โ Use LU Factorization
โ
โโ n โฅ 500
โโ Sparse? โ **Use Sparse CG** (99% memory savings)
โโ Dense + Need Speed? โ Use Gauss-Seidel (50ร faster)
โโ Dense + Need Precision? โ Use LU (but slow)
- Matrix must be diagonal dominant or symmetric positive definite
- Random matrices may not converge
- For general matrices, use preconditioners (advanced topic)
Edit main.cpp line 168:
std::vector<size_t> sizes = {10, 50, 100, 200, 500, 1000, 2000}; // Add 2000Modify in main.cpp when calling iterative solvers:
IterativeSolver::gaussSeidel(A, b, 1e-8, 5000); // tolerance, max_iterations// In main.cpp
Matrix A(3, 3);
A(0,0) = 4; A(0,1) = -1; A(0,2) = 0;
A(1,0) = -1; A(1,1) = 4; A(1,2) = -1;
A(2,0) = 0; A(2,1) = -1; A(2,2) = 4;
std::vector<double> b = {15, 10, 10};
auto x = GaussianElimination::solve(A, b);
Matrix::printVector(x, "Solution");#include "utils/sparse_matrix.h"
#include "linear_solvers/sparse_iterative_solver.h"
// Create tridiagonal matrix
SparseMatrix A = SparseMatrix::tridiagonal(1000, 4.0, -1.0);
std::vector<double> b = /* ... */;
// Solve with Conjugate Gradient
auto x = SparseIterativeSolver::conjugateGradient(A, b, 1e-6, 1000);
// Memory savings: 99.7% for 1000ร1000 tridiagonal#include "utils/matrix_analysis.h"
Matrix A = /* ... */;
// Comprehensive analysis
std::cout << MatrixAnalysis::analyze(A);
// Individual metrics
double cond = MatrixAnalysis::conditionNumber(A);
bool stable = MatrixAnalysis::isDiagonallyDominant(A);#include "utils/memory_profiler.h"
MemoryProfiler profiler;
profiler.start();
// Your code here
Matrix A = Matrix::random(1000, 1000);
profiler.updatePeak();
size_t peak = profiler.stop();
std::cout << "Peak: " << MemoryProfiler::formatBytes(peak);- Forward Elimination: Transform to upper triangular using row operations
- Partial Pivoting: Swap rows to improve numerical stability
- Back Substitution: Solve from bottom to top
- Decomposition: A = LU (Doolittle: L has 1s on diagonal)
- Forward Substitution: Ly = b
- Back Substitution: Ux = y
For each iteration:
For i = 1 to n:
x_i = (b_i - ฮฃ(a_ij * x_j)) / a_ii
(uses updated x values immediately)
For each iteration:
For i = 1 to n:
x_i_new = (b_i - ฮฃ(a_ij * x_j_old)) / a_ii
(uses only old x values)
The project includes comprehensive unit tests using Google Test framework:
# Build and run all tests
cd build
cmake ..
make
ctest --output-on-failure
# Run specific test suite
./test_gaussian # Direct solver tests
./test_sparse # Sparse matrix tests
./test_advanced # SOR/Cholesky/preconditioner testsTest Coverage:
- โ Gaussian Elimination (5 tests) - Simple systems, identity, diagonal dominant, error handling
- โ Sparse Matrices (4 tests) - Tridiagonal creation, multiplication, CG solver, memory efficiency
- โ Advanced Solvers (5 tests) - SOR convergence, Cholesky decomposition, preconditioners
- 100% pass rate across all test suites
We welcome contributions! Here's how you can help:
- Use the GitHub Issues page
- Provide clear description, expected vs actual behavior
- Include system info (OS, compiler, CMake version)
-
Fork the repository
git clone https://github.com/YOUR_USERNAME/optimization-and-search-cpp.git cd optimization-and-search-cpp -
Create a feature branch
git checkout -b feature/your-feature-name
-
Make your changes
- Follow existing code style (Google C++ Style Guide)
- Add unit tests for new features
- Update documentation (README, code comments)
- Ensure all tests pass:
ctest --output-on-failure
-
Commit and push
git add . git commit -m "Add: brief description of your changes" git push origin feature/your-feature-name
-
Open a Pull Request
- Describe what you've changed and why
- Reference any related issues
- Wait for code review
- ๐ Performance: GPU acceleration (CUDA/OpenCL), SIMD optimizations
- ๐ Algorithms: QR decomposition, GMRES, BiCGSTAB
- ๐งช Testing: More edge cases, integration tests, benchmarks on different hardware
- ๐ Documentation: Tutorials, algorithm explanations, usage examples
- ๐ Bug fixes: Check Issues
- Use meaningful variable names (
condition_numbernotcn) - Add comments for complex algorithms
- Keep functions focused (single responsibility)
- Follow const-correctness
- Use modern C++17 features where appropriate
- Iterative methods require diagonal dominant or SPD matrices for convergence
- Single-threaded implementation (OpenMP parallelization planned)
- No pivoting in LU factorization (may fail on some matrices)
- Cholesky requires manual verification of SPD property
- OpenMP parallelization for large matrices
- GitHub Actions CI/CD pipeline
- Additional methods (QR, GMRES, BiCGSTAB)
- GPU acceleration (CUDA/OpenCL)
- Incomplete LU preconditioner
- Automatic SPD detection for Cholesky
- Python bindings (pybind11)
- Golub, G. H., & Van Loan, C. F. (2013). Matrix Computations (4th ed.)
- Saad, Y. (2003). Iterative Methods for Sparse Linear Systems
- Press, W. H., et al. (2007). Numerical Recipes: The Art of Scientific Computing
This project is open source and available under the MIT License.
Talha Demir
- GitHub: @Talha-Dmr
This project was developed as part of a numerical methods course to understand the practical performance characteristics of different linear system solvers.
โญ If you find this project useful, please consider giving it a star!