1MatrixOps(3)          User Contributed Perl Documentation         MatrixOps(3)
2
3
4

NAME

6       PDL::MatrixOps -- Some Useful Matrix Operations
7

SYNOPSIS

9           $inv = $x->inv;
10
11           $det = $x->det;
12
13           ($lu,$perm,$par) = $x->lu_decomp;
14           $y = lu_backsub($lu,$perm,$z); # solve $x x $y = $z
15

DESCRIPTION

17       PDL::MatrixOps is PDL's built-in matrix manipulation code.  It contains
18       utilities for many common matrix operations: inversion, determinant
19       finding, eigenvalue/vector finding, singular value decomposition, etc.
20       PDL::MatrixOps routines are written in a mixture of Perl and C, so that
21       they are reliably present even when there is no FORTRAN compiler or
22       external library available (e.g.  PDL::Slatec or any of the PDL::GSL
23       family of modules).
24
25       Matrix manipulation, particularly with large matrices, is a challenging
26       field and no one algorithm is suitable in all cases.  The utilities
27       here use general-purpose algorithms that work acceptably for many cases
28       but might not scale well to very large or pathological (near-singular)
29       matrices.
30
31       Except as noted, the matrices are PDLs whose 0th dimension ranges over
32       column and whose 1st dimension ranges over row.  The matrices appear
33       correctly when printed.
34
35       These routines should work OK with PDL::Matrix objects as well as with
36       normal PDLs.
37

TIPS ON MATRIX OPERATIONS

39       Like most computer languages, PDL addresses matrices in (column,row)
40       order in most cases; this corresponds to (X,Y) coordinates in the
41       matrix itself, counting rightwards and downwards from the upper left
42       corner.  This means that if you print a PDL that contains a matrix, the
43       matrix appears correctly on the screen, but if you index a matrix
44       element, you use the indices in the reverse order that you would in a
45       math textbook.  If you prefer your matrices indexed in (row, column)
46       order, you can try using the PDL::Matrix object, which includes an
47       implicit exchange of the first two dimensions but should be compatible
48       with most of these matrix operations.  TIMTOWDTI.)
49
50       Matrices, row vectors, and column vectors can be multiplied with the
51       'x' operator (which is, of course, threadable):
52
53           $m3 = $m1 x $m2;
54           $col_vec2 = $m1 x $col_vec1;
55           $row_vec2 = $row_vec1 x $m1;
56           $scalar = $row_vec x $col_vec;
57
58       Because of the (column,row) addressing order, 1-D PDLs are treated as
59       _row_ vectors; if you want a _column_ vector you must add a dummy
60       dimension:
61
62           $rowvec  = pdl(1,2);            # row vector
63           $colvec  = $rowvec->(*1);         # 1x2 column vector
64           $matrix  = pdl([[3,4],[6,2]]);  # 2x2 matrix
65           $rowvec2 = $rowvec x $matrix;   # right-multiplication by matrix
66           $colvec  = $matrix x $colvec;   # left-multiplication by matrix
67           $m2      = $matrix x $rowvec;   # Throws an error
68
69       Implicit threading works correctly with most matrix operations, but you
70       must be extra careful that you understand the dimensionality.  In
71       particular, matrix multiplication and other matrix ops need nx1 PDLs as
72       row vectors and 1xn PDLs as column vectors.  In most cases you must
73       explicitly include the trailing 'x1' dimension in order to get the
74       expected results when you thread over multiple row vectors.
75
76       When threading over matrices, it's very easy to get confused about
77       which dimension goes where. It is useful to include comments with every
78       expression, explaining what you think each dimension means:
79
80               $x = xvals(360)*3.14159/180;        # (angle)
81               $rot = cat(cat(cos($x),sin($x)),    # rotmat: (col,row,angle)
82                          cat(-sin($x),cos($x)));
83

ACKNOWLEDGEMENTS

85       MatrixOps includes algorithms and pre-existing code from several
86       origins.  In particular, "eigens_sym" is the work of Stephen Moshier,
87       "svd" uses an SVD subroutine written by Bryant Marks, and "eigens" uses
88       a subset of the Small Scientific Library by Kenneth Geisshirt.  They
89       are free software, distributable under same terms as PDL itself.
90

NOTES

92       This is intended as a general-purpose linear algebra package for small-
93       to-mid sized matrices.  The algorithms may not scale well to large
94       matrices (hundreds by hundreds) or to near singular matrices.
95
96       If there is something you want that is not here, please add and
97       document it!
98

FUNCTIONS

100   identity
101         Signature: (n; [o]a(n,n))
102
103       Return an identity matrix of the specified size.  If you hand in a
104       scalar, its value is the size of the identity matrix; if you hand in a
105       dimensioned PDL, the 0th dimension is the size of the matrix.
106
107   stretcher
108         Signature: (a(n); [o]b(n,n))
109
110         $mat = stretcher($eigenvalues);
111
112       Return a diagonal matrix with the specified diagonal elements
113
114   inv
115         Signature: (a(m,m); sv opt )
116
117         $a1 = inv($a, {$opt});
118
119       Invert a square matrix.
120
121       You feed in an NxN matrix in $a, and get back its inverse (if it
122       exists).  The code is inplace-aware, so you can get back the inverse in
123       $a itself if you want -- though temporary storage is used either way.
124       You can cache the LU decomposition in an output option variable.
125
126       "inv" uses "lu_decomp" by default; that is a numerically stable
127       (pivoting) LU decomposition method.
128
129       OPTIONS:
130
131       •  s
132
133          Boolean value indicating whether to complain if the matrix is
134          singular.  If this is false, singular matrices cause inverse to
135          barf.  If it is true, then singular matrices cause inverse to return
136          undef.
137
138       •  lu (I/O)
139
140          This value contains a list ref with the LU decomposition,
141          permutation, and parity values for $a.  If you do not mention the
142          key, or if the value is undef, then inverse calls "lu_decomp".  If
143          the key exists with an undef value, then the output of "lu_decomp"
144          is stashed here (unless the matrix is singular).  If the value
145          exists, then it is assumed to hold the LU decomposition.
146
147       •  det (Output)
148
149          If this key exists, then the determinant of $a get stored here,
150          whether or not the matrix is singular.
151
152   det
153         Signature: (a(m,m); sv opt)
154
155         $det = det($a,{opt});
156
157       Determinant of a square matrix using LU decomposition (for large
158       matrices)
159
160       You feed in a square matrix, you get back the determinant.  Some
161       options exist that allow you to cache the LU decomposition of the
162       matrix (note that the LU decomposition is invalid if the determinant is
163       zero!).  The LU decomposition is cacheable, in case you want to re-use
164       it.  This method of determinant finding is more rapid than recursive-
165       descent on large matrices, and if you reuse the LU decomposition it's
166       essentially free.
167
168       OPTIONS:
169
170       •  lu (I/O)
171
172          Provides a cache for the LU decomposition of the matrix.  If you
173          provide the key but leave the value undefined, then the LU
174          decomposition goes in here; if you put an LU decomposition here, it
175          will be used and the matrix will not be decomposed again.
176
177   determinant
178         Signature: (a(m,m))
179
180         $det = determinant($x);
181
182       Determinant of a square matrix, using recursive descent (threadable).
183
184       This is the traditional, robust recursive determinant method taught in
185       most linear algebra courses.  It scales like "O(n!)" (and hence is
186       pitifully slow for large matrices) but is very robust because no
187       division is involved (hence no division-by-zero errors for singular
188       matrices).  It's also threadable, so you can find the determinants of a
189       large collection of matrices all at once if you want.
190
191       Matrices up to 3x3 are handled by direct multiplication; larger
192       matrices are handled by recursive descent to the 3x3 case.
193
194       The LU-decomposition method "det" is faster in isolation for single
195       matrices larger than about 4x4, and is much faster if you end up
196       reusing the LU decomposition of $a (NOTE: check performance and
197       threading benchmarks with new code).
198
199   eigens_sym
200         Signature: ([phys]a(m); [o,phys]ev(n,n); [o,phys]e(n))
201
202       Eigenvalues and -vectors of a symmetric square matrix.  If passed an
203       asymmetric matrix, the routine will warn and symmetrize it, by taking
204       the average value.  That is, it will solve for 0.5*($a+$a->mv(0,1)).
205
206       It's threadable, so if $a is 3x3x100, it's treated as 100 separate 3x3
207       matrices, and both $ev and $e get extra dimensions accordingly.
208
209       If called in scalar context it hands back only the eigenvalues.
210       Ultimately, it should switch to a faster algorithm in this case (as
211       discarding the eigenvectors is wasteful).
212
213       The algorithm used is due to J. vonNeumann, which was a rediscovery of
214       Jacobi's Method
215       <http://en.wikipedia.org/wiki/Jacobi_eigenvalue_algorithm> .
216
217       The eigenvectors are returned in COLUMNS of the returned PDL.  That
218       makes it slightly easier to access individual eigenvectors, since the
219       0th dim of the output PDL runs across the eigenvectors and the 1st dim
220       runs across their components.
221
222           ($ev,$e) = eigens_sym $x;  # Make eigenvector matrix
223           $vector = $ev->($n);       # Select nth eigenvector as a column-vector
224           $vector = $ev->(($n));     # Select nth eigenvector as a row-vector
225
226           ($ev, $e) = eigens_sym($x); # e-vects & e-values
227           $e = eigens_sym($x);        # just eigenvalues
228
229       eigens_sym ignores the bad-value flag of the input piddles.  It will
230       set the bad-value flag of all output piddles if the flag is set for any
231       of the input piddles.
232
233   eigens
234         Signature: ([phys]a(m); [o,phys]ev(l,n,n); [o,phys]e(l,n))
235
236       Real eigenvalues and -vectors of a real square matrix.
237
238       (See also "eigens_sym", for eigenvalues and -vectors of a real,
239       symmetric, square matrix).
240
241       The eigens function will attempt to compute the eigenvalues and
242       eigenvectors of a square matrix with real components.  If the matrix is
243       symmetric, the same underlying code as "eigens_sym" is used.  If
244       asymmetric, the eigenvalues and eigenvectors are computed with
245       algorithms from the sslib library.  If any imaginary components exist
246       in the eigenvalues, the results are currently considered to be invalid,
247       and such eigenvalues are returned as "NaN"s.  This is true for
248       eigenvectors also.  That is if there are imaginary components to any of
249       the values in the eigenvector, the eigenvalue and corresponding
250       eigenvectors are all set to "NaN".  Finally, if there are any repeated
251       eigenvectors, they are replaced with all "NaN"s.
252
253       Use of the eigens function on asymmetric matrices should be considered
254       experimental!  For asymmetric matrices, nearly all observed matrices
255       with real eigenvalues produce incorrect results, due to errors of the
256       sslib algorithm.  If your assymmetric matrix returns all NaNs, do not
257       assume that the values are complex.  Also, problems with memory access
258       is known in this library.
259
260       Not all square matrices are diagonalizable.  If you feed in a non-
261       diagonalizable matrix, then one or more of the eigenvectors will be set
262       to NaN, along with the corresponding eigenvalues.
263
264       "eigens" is threadable, so you can solve 100 eigenproblems by feeding
265       in a 3x3x100 array. Both $ev and $e get extra dimensions accordingly.
266
267       If called in scalar context "eigens" hands back only the eigenvalues.
268       This is somewhat wasteful, as it calculates the eigenvectors anyway.
269
270       The eigenvectors are returned in COLUMNS of the returned PDL (ie the
271       the 0 dimension).  That makes it slightly easier to access individual
272       eigenvectors, since the 0th dim of the output PDL runs across the
273       eigenvectors and the 1st dim runs across their components.
274
275               ($ev,$e) = eigens $x;  # Make eigenvector matrix
276               $vector = $ev->($n);   # Select nth eigenvector as a column-vector
277               $vector = $ev->(($n)); # Select nth eigenvector as a row-vector
278
279       DEVEL NOTES:
280
281       For now, there is no distinction between a complex eigenvalue and an
282       invalid eigenvalue, although the underlying code generates complex
283       numbers.  It might be useful to be able to return complex eigenvalues.
284
285           ($ev, $e) = eigens($x); # e'vects & e'vals
286           $e = eigens($x);        # just eigenvalues
287
288       eigens ignores the bad-value flag of the input piddles.  It will set
289       the bad-value flag of all output piddles if the flag is set for any of
290       the input piddles.
291
292   svd
293         Signature: (a(n,m); [o]u(n,m); [o,phys]z(n); [o]v(n,n))
294
295        ($u, $s, $v) = svd($x);
296
297       Singular value decomposition of a matrix.
298
299       "svd" is threadable.
300
301       Given an m x n matrix $a that has m rows and n columns (m >= n), "svd"
302       computes matrices $u and $v, and a vector of the singular values $s.
303       Like most implementations, "svd" computes what is commonly referred to
304       as the "thin SVD" of $a, such that $u is m x n, $v is n x n, and there
305       are <=n singular values. As long as m >= n, the original matrix can be
306       reconstructed as follows:
307
308           ($u,$s,$v) = svd($x);
309           $ess = zeroes($x->dim(0),$x->dim(0));
310           $ess->slice("$_","$_").=$s->slice("$_") foreach (0..$x->dim(0)-1); #generic diagonal
311           $a_copy = $u x $ess x $v->transpose;
312
313       If m==n, $u and $v can be thought of as rotation matrices that convert
314       from the original matrix's singular coordinates to final coordinates,
315       and from original coordinates to singular coordinates, respectively,
316       and $ess is a diagonal scaling matrix.
317
318       If n>m, "svd" will barf. This can be avoided by passing in the
319       transpose of $a, and reconstructing the original matrix like so:
320
321           ($u,$s,$v) = svd($x->transpose);
322           $ess = zeroes($x->dim(1),$x->dim(1));
323           $ess->slice("$_","$_").=$s->slice("$_") foreach (0..$x->dim(1)-1); #generic diagonal
324           $x_copy = $v x $ess x $u->transpose;
325
326       EXAMPLE
327
328       The computing literature has loads of examples of how to use SVD.
329       Here's a trivial example (used in PDL::Transform::map) of how to make a
330       matrix less, er, singular, without changing the orientation of the
331       ellipsoid of transformation:
332
333           { my($r1,$s,$r2) = svd $x;
334             $s++;             # fatten all singular values
335             $r2 *= $s;        # implicit threading for cheap mult.
336             $x .= $r2 x $r1;  # a gets r2 x ess x r1
337           }
338
339       svd ignores the bad-value flag of the input piddles.  It will set the
340       bad-value flag of all output piddles if the flag is set for any of the
341       input piddles.
342
343   lu_decomp
344         Signature: (a(m,m); [o]lu(m,m); [o]perm(m); [o]parity)
345
346       LU decompose a matrix, with row permutation
347
348         ($lu, $perm, $parity) = lu_decomp($x);
349
350         $lu = lu_decomp($x, $perm, $par);  # $perm and $par are outputs!
351
352         lu_decomp($x->inplace,$perm,$par); # Everything in place.
353
354       "lu_decomp" returns an LU decomposition of a square matrix, using
355       Crout's method with partial pivoting. It's ported from Numerical
356       Recipes. The partial pivoting keeps it numerically stable but means a
357       little more overhead from threading.
358
359       "lu_decomp" decomposes the input matrix into matrices L and U such that
360       LU = A, L is a subdiagonal matrix, and U is a superdiagonal matrix. By
361       convention, the diagonal of L is all 1's.
362
363       The single output matrix contains all the variable elements of both the
364       L and U matrices, stacked together. Because the method uses pivoting
365       (rearranging the lower part of the matrix for better numerical
366       stability), you have to permute input vectors before applying the L and
367       U matrices. The permutation is returned either in the second argument
368       or, in list context, as the second element of the list. You need the
369       permutation for the output to make any sense, so be sure to get it one
370       way or the other.
371
372       LU decomposition is the answer to a lot of matrix questions, including
373       inversion and determinant-finding, and "lu_decomp" is used by "inv".
374
375       If you pass in $perm and $parity, they either must be predeclared PDLs
376       of the correct size ($perm is an n-vector, $parity is a scalar) or
377       scalars.
378
379       If the matrix is singular, then the LU decomposition might not be
380       defined; in those cases, "lu_decomp" silently returns undef. Some
381       singular matrices LU-decompose just fine, and those are handled OK but
382       give a zero determinant (and hence can't be inverted).
383
384       "lu_decomp" uses pivoting, which rearranges the values in the matrix
385       for more numerical stability. This makes it really good for large and
386       even near-singular matrices. There is a non-pivoting version
387       "lu_decomp2" available which is from 5 to 60 percent faster for typical
388       problems at the expense of failing to compute a result in some cases.
389
390       Now that the "lu_decomp" is threaded, it is the recommended LU
391       decomposition routine.  It no longer falls back to "lu_decomp2".
392
393       "lu_decomp" is ported from Numerical Recipes to PDL. It should probably
394       be implemented in C.
395
396   lu_decomp2
397         Signature: (a(m,m); [o]lu(m,m))
398
399       LU decompose a matrix, with no row permutation
400
401         ($lu, $perm, $parity) = lu_decomp2($x);
402
403         $lu = lu_decomp2($x,$perm,$parity);   # or
404         $lu = lu_decomp2($x);                 # $perm and $parity are optional
405
406         lu_decomp($x->inplace,$perm,$parity); # or
407         lu_decomp($x->inplace);               # $perm and $parity are optional
408
409       "lu_decomp2" works just like "lu_decomp", but it does no pivoting at
410       all.  For compatibility with "lu_decomp", it will give you a
411       permutation list and a parity scalar if you ask for them -- but they
412       are always trivial.
413
414       Because "lu_decomp2" does not pivot, it is numerically unstable -- that
415       means it is less precise than "lu_decomp", particularly for large or
416       near-singular matrices.  There are also specific types of non-singular
417       matrices that confuse it (e.g. ([0,-1,0],[1,0,0],[0,0,1]), which is a
418       90 degree rotation matrix but which confuses "lu_decomp2").
419
420       On the other hand, if you want to invert rapidly a few hundred thousand
421       small matrices and don't mind missing one or two, it could be the
422       ticket.  It can be up to 60% faster at the expense of possible failure
423       of the decomposition for some of the input matrices.
424
425       The output is a single matrix that contains the LU decomposition of $a;
426       you can even do it in-place, thereby destroying $a, if you want.  See
427       "lu_decomp" for more information about LU decomposition.
428
429       "lu_decomp2" is ported from Numerical Recipes into PDL.
430
431   lu_backsub
432         Signature: (lu(m,m); perm(m); b(m))
433
434       Solve a x = b for matrix a, by back substitution into a's LU
435       decomposition.
436
437         ($lu,$perm,$par) = lu_decomp($x);
438
439         $x = lu_backsub($lu,$perm,$par,$y);  # or
440         $x = lu_backsub($lu,$perm,$y);       # $par is not required for lu_backsub
441
442         lu_backsub($lu,$perm,$y->inplace); # modify $y in-place
443
444         $x = lu_backsub(lu_decomp($x),$y); # (ignores parity value from lu_decomp)
445
446       Given the LU decomposition of a square matrix (from "lu_decomp"),
447       "lu_backsub" does back substitution into the matrix to solve "a x = b"
448       for given vector "b".  It is separated from the "lu_decomp" method so
449       that you can call the cheap "lu_backsub" multiple times and not have to
450       do the expensive LU decomposition more than once.
451
452       "lu_backsub" acts on single vectors and threads in the usual way, which
453       means that it treats $y as the transpose of the input.  If you want to
454       process a matrix, you must hand in the transpose of the matrix, and
455       then transpose the output when you get it back. that is because pdls
456       are indexed by (col,row), and matrices are (row,column) by convention,
457       so a 1-D pdl corresponds to a row vector, not a column vector.
458
459       If $lu is dense and you have more than a few points to solve for, it is
460       probably cheaper to find "a^-1" with "inv", and just multiply "x = a^-1
461       b".) in fact, "inv" works by calling "lu_backsub" with the identity
462       matrix.
463
464       "lu_backsub" is ported from section 2.3 of Numerical Recipes.  It is
465       written in PDL but should probably be implemented in C.
466
467   simq
468         Signature: ([phys]a(n,n); [phys]b(n); [o,phys]x(n); int [o,phys]ips(n); int flag)
469
470       Solution of simultaneous linear equations, "a x = b".
471
472       $a is an "n x n" matrix (i.e., a vector of length "n*n"), stored row-
473       wise: that is, "a(i,j) = a[ij]", where "ij = i*n + j".
474
475       While this is the transpose of the normal column-wise storage, this
476       corresponds to normal PDL usage.  The contents of matrix a may be
477       altered (but may be required for subsequent calls with flag = -1).
478
479       $y, $x, $ips are vectors of length "n".
480
481       Set "flag=0" to solve.  Set "flag=-1" to do a new back substitution for
482       different $y vector using the same a matrix previously reduced when
483       "flag=0" (the $ips vector generated in the previous solution is also
484       required).
485
486       See also "lu_backsub", which does the same thing with a slightly less
487       opaque interface.
488
489       simq ignores the bad-value flag of the input piddles.  It will set the
490       bad-value flag of all output piddles if the flag is set for any of the
491       input piddles.
492
493   squaretotri
494         Signature: (a(n,n); b(m))
495
496       Convert a symmetric square matrix to triangular vector storage.
497
498       squaretotri does not process bad values.  It will set the bad-value
499       flag of all output piddles if the flag is set for any of the input
500       piddles.
501

AUTHOR

503       Copyright (C) 2002 Craig DeForest (deforest@boulder.swri.edu), R.J.R.
504       Williams (rjrw@ast.leeds.ac.uk), Karl Glazebrook
505       (kgb@aaoepp.aao.gov.au).  There is no warranty.  You are allowed to
506       redistribute and/or modify this work under the same conditions as PDL
507       itself.  If this file is separated from the PDL distribution, then the
508       PDL copyright notice should be included in this file.
509
510
511
512perl v5.32.1                      2021-02-15                      MatrixOps(3)
Impressum