matrix equations for a spline

matrix equation for an open curve

The matrix equation to be solved is $$ \begin{pmatrix} b_{0} & c_0 & & & 0 \\ a_{1} & b_{1} & c_1 & & \\ & a_{2} & b_{2} & \ddots & \\ & & \ddots & \ddots & c_{n-1} \\ 0 & & & a_n & b_n \end{pmatrix} \begin{pmatrix} P_{1,0} \\ P_{1,1} \\ P_{1,2} \\ \vdots \\ P_{1,n} \end{pmatrix} = \begin{pmatrix} r_{0} \\ r_{1} \\ r_{2} \\ \vdots \\ r_{n} \end{pmatrix} \quad\quad\quad (12) $$ in which $$ \begin{align} b_{0} &= 2 &\\ c_{0} &= w_0/w_1 &\\ a_{i} &= w_i^2 & i \in \{1,\dots, n-1\} \\ b_{i} &= 2w_{i-1}(w_{i-1}+w_i) & i \in \{1,\dots, n-1\} \\ c_{i} &= (w_{i-1})^2w_i/w_{i+1} & i \in \{1,\dots, n-1\} \\ a_{n} &= 1 &\\ b_{n} &= 2 w_{n-1}/w_n& \end{align} $$ and $$ \begin{align} r_0 &= K_{0} + K_1 \left( 1+ {w_{0} \over w_{1}} \right) \\ r_i &= K_{i}\left( w_{i-1} + w_{i}\right)^2 + K_{i+1} w_{i-1}^2 \left( 1+ {w_{i} \over w_{i+1}} \right) & i \in \{1,\dots, n-1\} \\ r_n &= K_n \left( 1+2 {w_{n-1} \over w_{n}} \right) \end{align} $$ (corrected on 2018-08-16 after a comment by R.B.A. van Hoek)
The equation must be solved 2 times: 1 time for the \(x\) coordinates, and 1 time for the \(y\) coordinates of \(\mathbf P_{1,i}\).

matrix equation for a closed curve

In this case, \(n\) knots will be labeled \(0,1,\dots,n-1\). $$ \begin{pmatrix} b_{0} & c_0 & & & a_0 \\ a_{1} & b_{1} & c_1 & & \\ & a_{2} & b_{2} & \ddots & \\ & & \ddots & \ddots & c_{n-2} \\ c_{n-1} & & & a_{n-1} & b_{n-1} \end{pmatrix} \begin{pmatrix} P_{1,0} \\ P_{1,1} \\ P_{1,2} \\ \vdots \\ P_{1,n-1} \end{pmatrix} = \begin{pmatrix} r_{0} \\ r_{1} \\ r_{2} \\ \vdots \\ r_{n-1} \end{pmatrix} \quad\quad\quad (13)$$ Again we have $$ \begin{align} a_{i} &= w_i^2 & i \in \{0,\dots, n-1\} \\ b_{i} &= 2w_{i-1}(w_{i-1}+w_i) & i \in \{1,\dots, n-1\} \\ c_{i} &= (w_{i-1})^2w_i/w_{i+1} & i \in \{1,\dots, n-2\} \\ r_i &= K_{i}\left( w_{i-1} + w_{i}\right)^2 + K_{i+1} w_{i-1}^2 \left( 1+ {w_{i} \over w_{i+1}} \right) & i \in \{1,\dots, n-2\} \\ \end{align} $$ Of course, we use index \(0\) in stead of \(n\), so the formulas yield: $$ \begin{align} b_{0} &= 2w_{n-1}(w_{n-1}+w_0) \\ c_{0} &= (w_{n-1})^2w_0/w_{1} \\ c_{n-1} &= (w_{n-2})^2w_{n-1}/w_{0} \\ r_0 &= K_{0}\left( w_{n-1} + w_{0}\right)^2 + K_{1} w_{n-1}^2 \left( 1+ {w_{0} \over w_{1}} \right) \\ r_{n-1} &= K_{n-1}\left( w_{n-2} + w_{n-1}\right)^2 + K_{0} w_{n-2}^2 \left( 1+ {w_{n-1} \over w_{0}} \right) \end{align} $$

Gaussian elimination

The equation (12) can be solved using Gaussian elimination. Because the matrix for the open curve is tri-diagonal the Thomas algorithm can be used.
For a looped curve (equation (13)), I will describe the algorithm below.

The non-zero entries of the matrix will be stored in arrays a, b and c with indices 0 till n-1.
The right-hand-side is the array r with indices 0 till n-1.
During Gaussian elimination, the elements in the most right column of the matrix (under \(a_0\)) will change and I will store them in the array u with indices 0 till n-2.
The elements on the lowest row will also change, but become zero again. So, in stead of an array L with indices 0 till n-2, I use a single variable L.
In this way, the algorithm becomes:

u[0] = a[0]
L = c[n-1]
for (i = 0; i < n-3; i++)
{
	m1 = a[i+1]/b[i];
	b[i+1] -= m1 * c[i];
	// last column 
	u[i+1] = -m1 * u[i]

	// last row : 
	m2 = L/b[i]  
	b[n-1] -= m2 * u[i]
	L = - m2 * c[i] 

	// right-hand side
	r[i+1] -= m1 * r[i];
	r[n-1] -= m2 * r[i]
}
After this, the matrix equation has become $$ \begin{pmatrix} b_{0} & c_0 & & & & u_0 \\ 0 & b_{1} & c_1 & & & u_1\\ & \ddots & \ddots & \ddots & & \vdots\\ & & 0 & b_{n-3} & c_{n-3} & u_{n-3}\\ & & & a_{n-2} & b_{n-2} & c_{n-2} \\ 0 & & & L & a_{n-1} & b_{n-1} \end{pmatrix} \begin{pmatrix} P_{1,0} \\ P_{1,1} \\ P_{1,2} \\ \vdots \\ P_{1,n-1} \end{pmatrix} = \begin{pmatrix} r_{0} \\ r_{1} \\ r_{2} \\ \vdots \\ r_{n-1} \end{pmatrix} $$ So the next steps must be (note that i = n-3)
m1 = a[i+1]/b[i];
b[i+1] -= m1 * c[i];
// last column 
c[i+1] -= m1 * u [i]

// last row 
m2 = L/b[i]  
b[n-1] -= m2 * u[i]
a[n-1] -= m2 * c[i]

// right-hand side
r[i+1] -= m1 * r[i];
r[n-1] -= m2 * r[i]
which yields $$ \begin{pmatrix} b_{0} & c_0 & & & & u_0 \\ 0 & b_{1} & c_1 & & & u_1\\ & \ddots & \ddots & \ddots & & \vdots\\ & & 0 & b_{n-3} & c_{n-3} & u_{n-3}\\ & & & 0 & b_{n-2} & c_{n-2} \\ 0 & & & 0 & a_{n-1} & b_{n-1} \end{pmatrix} \begin{pmatrix} P_{1,0} \\ P_{1,1} \\ P_{1,2} \\ \vdots \\ P_{1,n-1} \end{pmatrix} = \begin{pmatrix} r_{0} \\ r_{1} \\ r_{2} \\ \vdots \\ r_{n-1} \end{pmatrix} $$ After
i = n-2
m = a[i+1]/b[i];
b[i+1] -= m * c[i];
r[i+1] -= m * r[i];
this becomes $$ \begin{pmatrix} b_{0} & c_0 & & & & u_0 \\ 0 & b_{1} & c_1 & & & u_1\\ & \ddots & \ddots & \ddots & & \vdots\\ & & 0 & b_{n-3} & c_{n-3} & u_{n-3}\\ & & & 0 & b_{n-2} & c_{n-2} \\ 0 & & & & 0 & b_{n-1} \end{pmatrix} \begin{pmatrix} P_{1,0} \\ P_{1,1} \\ P_{1,2} \\ \vdots \\ P_{1,n-1} \end{pmatrix} = \begin{pmatrix} r_{0} \\ r_{1} \\ r_{2} \\ \vdots \\ r_{n-1} \end{pmatrix} $$ Then the backward substitution becomes easy:
x[n-1] = r[n-1]/b[n-1];
x[n-2] = (r[n-2] - c[n-2] * x[n-1]) / b[n-2];
for (i = n - 3; i >= 0; --i)
{	x[i] = (r[i] - c[i] * x[i+1]-u[i]*x[n-1]) / b[i];
}
Previous