The following module in Forth computes the "similar" matrix, in
tridiagonal form, for a real square matrix, i.e. it tridiagonalizes the
input matrix using a series of similarity transformations. Similarity
transformations preserve many properties of the original matrix, such as
eigenvalues, determinant, trace, etc. -- a nice video explaining this
may be viewed here:
https://www.youtube.com/watch?v=L1a6yb3vjIk
The Forth code here implements the procedure given on the web page,
https://en.wikipedia.org/wiki/Householder_transformation
and reduces the original N by N matrix into tridiagonal form through a
series of Householder transformations. The example on the page above is
used within the test code.
Tridiagonalization may be used as a first step in computing the
eigenvalues and eigenvectors of a matrix, so this algorithm may be
useful as the first step, in conjunction with other well-known
algorithms for obtaining the eigenvalues/eigenvectors. The present
implementation does not compute ad save the accumulated similarity
transform, which would be needed for obtaining eigenvectors of the
original matrix. I also don't know what types of numerical instabilities
it may suffer, relative to similar routines from EISPACK or LAPACK, and
I don't know its relative efficiency in comparison with those routines
(e.g. tred2 from EISPACK), but it's a starting point.
The code is designed to work with the Forth Scientific Library, with an
extra matrix multiplication module (mmul.4th), and using the portable
modules framework provided with kForth (kForth-64). It should be easy to
use on modern Forth systems.
--
Krishna Myneni
tridiag.4th
--- start of file ---
\ tridiag.4th
\
\ Tridiagonalize a square matrix using a series of Householder
\ transforms. The input matrix is replaced by its similar
\ tridiagonal matrix.
\
\ Copyright 2022 Krishna Myneni. Permission is granted by the
\ author to use this software for any application provided this
\ copyright notice is preserved.
\
\ Glossary:
\
\ }}TRIDIAG ( N amatrix -- )
\
\ See example(s) of use in test code.
\
\ References:
\ 1. Wikipedia entry on Householder transformation,
\
https://en.wikipedia.org/wiki/Householder_transformation
\
\ 2. Wikipedia entry on matrix similarity,
\
https://en.wikipedia.org/wiki/Matrix_similarity
\
\ Requires:
\ fsl/fsl-util
\ fsl/dynmem
\ fsl/extras/mmul
\
BEGIN-MODULE
BASE @
[undefined] fsquare [IF] : fsquare fdup f* ; [THEN]
FLOAT DMATRIX Ap{{
FLOAT DMATRIX P{{
FLOAT DARRAY v{
fvariable alpha
fvariable 2r
0 value N
0 ptr AA{{
Public:
: }}tridiag ( N a -- )
\ Initialization
to AA{{ to N
N 2- 0 <= IF EXIT THEN
& v{ N }malloc
& P{{ N N }}malloc
& Ap{{ N N }}malloc
malloc-fail? IF 1 throw THEN
N 2- 0 DO
0.0e0 N I 1+ DO AA{{ I J }} f@ fsquare f+ LOOP fsqrt
AA{{ I 1+ I }} f@ f0< IF fnegate THEN fnegate fdup alpha f!
fdup AA{{ I 1+ I }} f@ f- f* 2.0e0 f* fsqrt 2r f!
\ Find reflection plane normal vector, v{
I 1+ 0 DO 0.0e0 v{ I } f! LOOP
AA{{ I 1+ I }} f@ alpha f@ f- 2r f@ f/ v{ I 1+ } f!
N I 2+ DO AA{{ I J }} f@ 2r f@ f/ v{ I } f! LOOP
\ Find similarity transform matrix, P{{, for reflection about plane
N 0 DO
N 0 DO
v{ J } f@ v{ I } f@ f* 2.0e0 f* fnegate
I J = IF 1.0e0 f+ THEN P{{ J I }} f!
LOOP
LOOP
\ Apply similarity transformation to matrix, AA{{
AA{{ P{{ Ap{{ N N N df_mmul
P{{ Ap{{ AA{{ N N N df_mmul
LOOP
\ cleanup
& Ap{{ }}free
& P{{ }}free
& v{ }free
;
BASE !
END-MODULE
TEST-CODE? [IF]
[UNDEFINED] T{ [IF] include ttester.4th [THEN]
BASE @ DECIMAL
1e-14 rel-near f!
1e-14 abs-near f!
set-near
\ Test case: 4 x 4 real, symmetric matrix (see ref. [1]).
4 4 FLOAT MATRIX A{{
4e 1e -2e 2e
1e 2e 0e 1e
-2e 0e 3e -2e
2e 1e -2e -1e
4 4 A{{ }}fput
CR
TESTING }}TRIDIAG
4 A{{ }}tridiag
t{ A{{ 0 0 }} f@ -> 4.0e0 r}t
t{ A{{ 0 1 }} f@ -> -3.0e0 r}t
t{ A{{ 0 2 }} f@ -> 0.0e0 r}t
t{ A{{ 0 3 }} f@ -> 0.0e0 r}t
t{ A{{ 1 0 }} f@ -> A{{ 0 1 }} f@ r}t
t{ A{{ 1 1 }} f@ -> 10.0e0 3.0e0 f/ r}t
t{ A{{ 1 2 }} f@ -> -5.0e0 3.0e0 f/ r}t
t{ A{{ 1 3 }} f@ -> 0.0e0 r}t
t{ A{{ 2 0 }} f@ -> 0.0e0 r}t
t{ A{{ 2 1 }} f@ -> A{{ 1 2 }} f@ r}t
t{ A{{ 2 2 }} f@ -> -33.0e0 25.0e0 f/ r}t
t{ A{{ 2 3 }} f@ -> 68.0e0 75.0e0 f/ r}t
t{ A{{ 3 0 }} f@ -> 0.0e0 r}t
t{ A{{ 3 1 }} f@ -> 0.0e0 r}t
t{ A{{ 3 2 }} f@ -> A{{ 2 3 }} f@ r}t
t{ A{{ 3 3 }} f@ -> 149.0e0 75.0e0 f/ r}t
BASE !
[THEN]
--- end of file ---
test-tridiag.4th
--- start of file ---
\ test-tridiag.4th
include ans-words
include modules
include fsl/fsl-util
include fsl/dynmem
include fsl/extras/mmul
true to test-code?
include fsl/extras/tridiag