Develop a solver for tridiagonal linear systems of equations using C++ and integrate it with Python through pybind11. This exercise involves writing code to describe a problem that needs solving and implementing the linear solver.
Consider a linear system of the form
Thomas algorithm, also known as the tridiagonal matrix algorithm (TDMA), is a simplified form of Gaussian elimination that is specifically designed to efficiently solve tridiagonal systems of equations.
A tridiagonal system is one in which each row of the matrix A involves at most three elements: one on the diagonal, one immediately above the diagonal (superdiagonal), and one immediately below the diagonal (subdiagonal).
Consider a tridiagonal system of n linear equations, whose
a[i]*u[i-1] + b[i]*u[i] + c[i]*u[i+1] = f[i], for i = 0, 1, ..., n-1,
where:
-
a[i]is the subdiagonal element, witha[0]being undefined, -
b[i]is the diagonal element, -
c[i]is the superdiagonal element, withc[n-1]being undefined, -
u[i]is the$i$ -th element of the unknown vector, -
f[i]is the$i$ -th element of the right-hand side vector.
The goal is to find the solution vector u.
The steps of the Thomas algorithm are:
// Step 1.
for i = 1 to n-1:
m = a[i] / b[i-1]
b[i] = b[i] - m * c[i-1]
f[i] = f[i] - m * f[i-1]
// Step 2.
u[n-1] = f[n-1] / b[n-1]
for i = n-1 down to 1:
u[i-1] = (f[i-1] - c[i-1] * u[i]) / b[i-1]
The following equation can be used to model temperature diffusion in a 1D slab:
where
Consider a domain
By dividing the domain into
where
The above linear system is tridiagonal, thus it can be solved using the Thomas algorithm.
For a concrete example involving the heat equation, consider the following data:
-
(5 points) Implement an abstract
Matrixclass:- Implement an abstract
Matrixclass in C++, defining common matrix attributes and (possibly pure virtual) methods, such as getting the number of rows and columns, accessing elements, printing, and whatever functionality you find relevant using class methods and/or friend functions. - Include a pure virtual method
std::vector<double> solve(const std::vector<double> &f)that solves a linear system given a right-hand side$f$ and returns its solution. - Derive a
TridiagonalMatrixclass fromMatrix. Implement proper constructors to initialize it given the diagonal vectorsa,b, andc. Override thesolvemethod to implement the Thomas algorithm. - Check size compatibility via exception handling.
- Implement an abstract
-
(3 points) Solve the heat diffusion problem:
- Create a class
HeatDiffusionrepresenting the heat diffusion problem and exposing its relevant parameters (domain, boundary conditions, forcing term$f$ ). - Use the
TridiagonalMatrixclass to solve the heat equation from a givenHeatDiffusionobject instance. The wayHeatDiffusionandTridiagonalMatrixclasses interact (e.g., inheritance, composition, ...) is up to you. Explain your design choices. - Validate the solution against the exact solution by computing the error
$\left|u - u_\mathrm{ex}\right|$ in Euclidean norm to assess the correctness of the implementation.
- Create a class
-
(2 points) Configuration and compilation
- Develop a CMake script for easy compilation of the C++ library.
- Provide clear instructions on compiling the library.
-
(5 points) Python bindings using pybind11:
- Bind the C++ functions, classes and their methods to Python, properly handling exceptions.
- Ensure the Python interface is user-friendly and adheres to Python conventions.
- Write a Python script that solves the heat equation using the provided C++ solver exposed through pybind11. Plot the numerical and exact solutions
$u(x)$ and$u_\mathrm{ex}(x)$ vs.$x$ for visual comparison. - Validate your implementation against the
solvefunction fromnumpy.linalgand/or against thesolve_bandedfunction fromscipy.linalg.
-
(Bonus)
ThomasSolverclass development:- Use muParserX in
HeatDiffusionto parse the functions$f(x)$ and$u_\mathrm{ex}(x)$ from input strings. - Define
ThomasSolveras a template class to allow it to work with any matrix type that supports the necessary operations (accessing elements, etc.). The template parameter represents the matrix type. - Implement the Thomas algorithm within the
ThomasSolverclass, making sure the implementation does not assume anything specific about the matrix type beyond the necessary operations. - Instantiate the
ThomasSolverclass withTridiagonalMatrixand with Eigen'sSparseMatrixXdclass. - Use
setuptoolsto setup the build process for the Python bindings. - Write tests for both the C++ and the Python implementation.
- Use muParserX in