As alluded to in the Gaussian Elimination chapter, the Thomas Algorithm (or TDMA, Tri-Diagonal Matrix Algorithm) allows for programmers to massively cut the computational cost of their code from $$ O(n^3)$$ to
This matrix shape is called Tri-Diagonal (excluding the right-hand side of our system of equations, of course!).
Now, at first, it might not be obvious how this helps. Well, firstly, it makes the system easier to encode: we may divide it into four separate vectors corresponding to
We'll start by applying mechanisms familiar to those who have read the Gaussian Elimination chapter.
Our first goal is to eliminate the
Let's assume that we found a way to transform the first
$$ \begin{array}{ccccccc|c} & & \ddots & & & & & \ (i-1) & & 0 & 1 & c'{i-1} & & & d'{i-1} \ (i) & & & a_i & b_i & c_i & & d_i \ & & & & & \ddots & & \end{array} $$
Let's transform row
Step one: eliminate
$$ \left{ \begin{align} a^_i &= 0 \ b^i &= b_i - a_i \times c'{i-1} \ c^_i &= c_i \ d^i &= d_i - a_i \times d'{i-1} \end{align} \right. $$
Step two: get
$$ \left{ \begin{align} a'_i &= 0 \ b'i &= 1 \ c'i &= \frac{c_i}{b_i - a_i \times c'{i-1}} \ d'i &= \frac{d_i - a_i \times d'{i-1}}{b_i - a_i \times c'{i-1}} \end{align} \right. $$
Brilliant! With the last two formula, we can calculate all the
Of course, what we really need are the solutions
If we express our system in terms of equations instead of a matrix, we get
$$ x_i + c'i \times x{i+1} = d'_i $$
plus the last row that is even simpler:
$$ x_i = d'_i - c'i \times x{i+1} $$
and that's all there is to it. We can calculate all the
Overall, we only need two passes, and that's why our algorithm is
{% method %} {% sample lang="jl" %} import, lang:"julia" {% sample lang="c" %} import, lang:"c" {% sample lang="py" %} import, lang:"python" {% sample lang="scratch" %} You will find this algorithm implemented in this project.
{% sample lang="java" %} [import, lang:"java"](code/java/Thomas.java) {% sample lang="hs" %} [import, lang:"haskell"](code/haskell/thomas.hs) {% sample lang="go" %} [import, lang:"go"](code/go/thomas.go) {% sample lang="v" %} [import, lang:"v"](code/v/thomas.v) {% sample lang="swift" %} [import, lang:"swift"](code/swift/thomas.swift) {% sample lang="php" %} [import, lang:"php"](code/php/thomas.php) {% sample lang="nim" %} [import, lang:"nim"](code/nim/thomas_algorithm.nim) {% sample lang="cpp" %} [import, lang:"cpp"](code/cpp/thomas.cpp) {% sample lang="lua" %} [import, lang:"lua"](code/lua/thomas.lua) {% sample lang="crystal" %} [import, lang:"crystal"](code/crystal/thomas.cr) {% sample lang="kotlin" %} [import, lang:"kotlin"](code/kotlin/thomas.kt) {% sample lang="lisp" %} [import, lang:"lisp"](code/clisp/thomas.lisp) {% sample lang="ruby" %} [import, lang="ruby"](code/ruby/thomas.rb) {% sample lang="js" %} [import, lang:"javascript"](code/javascript/thomas.js) {% sample lang="rs" %} [import, lang:"rust"](code/rust/thomas.rs) {% endmethod %} <script> MathJax.Hub.Queue(["Typeset",MathJax.Hub]); </script>The code examples are licensed under the MIT license (found in LICENSE.md).
The text of this chapter was written by James Schloss and is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
After initial licensing (#560), the following pull requests have modified the text or graphics of this chapter:
- none