[VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
|
09-22-2023, 08:22 PM
Post: #1
|
|||
|
|||
[VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Hi all,
Welcome to this second part of my latest thread SRC #015 - HP-15C & clones: Big NxN Matrix Inverse & Determinant, which I created to commemorate the availability of the HP-15C Collector's Edition.
However, in the particular case of complex matrix inversion we can do better than 6x6, as we'll see now. The Problem The approach that Werner and J-F Garnier followed in Part 1 for inverting complex matrices is based in the technique featured in both the HP-15C CE Owner's Handbook (p.165) and the Advanced Functions Handbook (p.128,) consisting in converting the NxN complex matrix to a 2Nx2N real matrix, which is then dealt with by using the built-in functions for real matrices, as well as pre- and post-applying a number of ad-hoc transformations (MATRIX 2, MATRIX 3, Py,x, Cy,x.) This is most fine and dandy but it has a number of serious problems, among them:
My Solution Once more, an entirely new strategy is needed. The main problem is that conversion to a 2Nx2N real matrix uses 4x the memory that an NxN real matrix would need, instead of 2x, but implementing an LU-based procedure would result in a long program much slower than the 2Nx2N approach. To sidestep this problem I use an approach which avoids wasting memory by not converting the NxN complex matrix to a 2Nx2N real one, while also using the built-in microcode real inversion instruction (1/x) for maximum speed, making sure it never has to invert a matrix larger than 8x8. Enter split complex matrices. A split complex matrix is an NxN complex matrix M considered to be split into two real NxN matrices A, B, containing the real and imaginary parts, respectively, of the complex elements of M, like this: │ 5 + 3i 4 + 7i 8 1 + 2i 6 + 6i │ │ 7 + 2i 5i 3 + 4i 8 + i 1 │ M = │ 8 + 4i 2 + 5i 6 + 7i 3 + 8i 5 │ = A + iB │ 6 + i 4 + 2i 3 + 7i 4 + 2i 6 + 5i │ │ 3 + 7i i 8 + 7i 1 + 3i 2 + 4i │ where A (real parts) and B (imaginary parts) are: │ 5 4 8 1 6 │ │ 3 7 0 2 6 │ │ 7 0 3 8 1 │ │ 2 5 4 1 0 | A = │ 8 2 6 3 5 │ , B = │ 4 5 7 8 0 │ │ 6 4 3 4 6 │ │ 1 2 7 2 5 │ │ 3 0 8 1 2 │ │ 7 1 7 3 4 │ and as it happens, there are efficient algorithms to invert such split complex matrices by interacting directly with their parts stored in real matrices, thus no complex arithmetic is ever needed as all computations are carried out in the real domain, with a noticeable speed advantage which is further increased because my routine spends most of its time executing microcode, not RPN user code. Another important consideration is code size. Like the original one, the HP-15C CE has no way to save/load programs to/from mass storage (say by connecting to a laptop,) thus entering programs has to be done by manually typing them in, which becomes exceedingly bothersome, time-consuming and error-prone when the programs are long (say 100-200 steps or more,) and all you see are numeric keycodes. It's one thing if you're using a single long program all the time but entirely another if you want to use your CE for various purposes requiring assorted programs, as eventually you'll be forced to erase one to make room for another and this will get utterly inconvenient, slow and annoying pretty soon. To wit, a program might be a fine achievement and work well but if the user has to painstakingly key in a large number of program steps to use it, chances are it won't be used much if at all, not even to just check it out. Thus, I think it's important that my solution is very short, to maximize its potential use and minimize the burden of loading it into the calculator. The implementation: Complex Matrix Inversion up to 8x8 This 31-step (32-byte) routine will invert in place an NxN split complex matrix M for 1 ≤ N ≤ 8 (subject to available memory.) It takes no inputs but the caller (the user or another program) must have previously dimensioned and populated the two real matrices A, B with the corresponding parts of M's elements. Once it returns, the original values in A, B will have been replaced with those of the complex inverse matrix, which the user or the caller program may then proceed to output or use as desired. In other words, this routine can be called from the keyboard or another program (in which case it could be directly embedded into it if called from a single location) but it doesn't perform any input or output operations, it just does the inversion in place. Program listing LBL C 001- 42,21,13 RCL MATRIX A 002- 45,16,11 RCL MATRIX B 003- 45,16,12 RESULT E 004- 42,26,15 + 005- 40 1/x 006- 15 RCL MATRIX B 007- 45,16,12 RCL MATRIX A 008- 45,16,11 RESULT B 009- 42,26,12 - 010- 30 X<>Y 011- 34 RESULT A 012- 42,26,11 x 013- 20 CHS 014- 16 LASTX 015- 43 36 RESULT E 016- 42,26,15 1/x 017- 15 X<>Y 018- 34 RCL MATRIX B 019- 45,16,12 MATRIX 6 020- 42,16, 6 1/x 021- 15 RCL MATRIX A 022- 45,16,11 RESULT B 023- 42,26,12 x 024- 20 RESULT A 025- 42,26,11 + 026- 40 LASTX 027- 43 36 RCL MATRIX E 028- 45,16,15 RESULT B 029- 42,26,12 - 030- 30 RTN 031- 43 32 Notes:
This means that matrices 9x9 or larger can't be tackled using this routine on any currently existing device. However, it might be possible that some future patch would override those restrictions, in which case this routine would invert complex matrices larger than 8x8 without any modifications.
Worked example The following example can be run on the HP-15C CE (Collector's Edition) in its 96- or 192-regs Mode, as well as in any physical/virtual clone with at least 80 regs allocatable.
│ 5 + 3i 4 + 7i 8 1 + 2i 6 + 6i │ │ 7 + 2i 5i 3 + 4i 8 + i 1 │ M = │ 8 + 4i 2 + 5i 6 + 7i 3 + 8i 5 │ │ 6 + i 4 + 2i 3 + 7i 4 + 2i 6 + 5i │ │ 3 + 7i i 8 + 7i 1 + 3i 2 + 4i │ - The A (real parts) and B (imaginary parts) matrices are: │ 5 4 8 1 6 │ │ 3 7 0 2 6 │ │ 7 0 3 8 1 │ │ 2 5 4 1 0 | A = │ 8 2 6 3 5 │ , B = │ 4 5 7 8 0 │ │ 6 4 3 4 6 │ │ 1 2 7 2 5 │ │ 3 0 8 1 2 │ │ 7 1 7 3 4 │ - Ensure disabled complex stack and set 4 decimal places: CF 8, FIX 4 - Allocate all memory to matrices, initialize them and dimension the real/imag parts A, B to 5x5: 1, DIM (i), MATRIX 0 5, ENTER, DIM A, DIM B - Store the real parts of M's elements into matrix A: USER, MATRIX 1 5 STO A, 4 STO A, 8 STO A, 1 STO A, 6 STO A, 7 STO A, 0 STO A, 3 STO A, 8 STO A, 1 STO A, 8 STO A, 2 STO A, 6 STO A, 3 STO A, 5 STO A, 6 STO A, 4 STO A, 3 STO A, 4 STO A, 6 STO A, 3 STO A, 0 STO A, 8 STO A, 1 STO A, 2 STO A - Store their imaginary parts into matrix B: 3 STO B, 7 STO B, 0 STO B, 2 STO B, 6 STO B, 2 STO B, 5 STO B, 4 STO B, 1 STO B, 0 STO B, 4 STO B, 5 STO B, 7 STO B, 8 STO B, 0 STO B, 1 STO B, 2 STO B, 7 STO B, 2 STO B, 5 STO B, 7 STO B, 1 STO B, 7 STO B, 3 STO B, 4 STO B - Compute in-place the complex inverse matrix M': GSB C -> B 5 5 {in 0.93"} - Recall the inverse matrix elements from A and B: Real parts: RCL A: -0.1197, RCL A: -0.0070, RCL A: 0.0635, RCL A: 0.0322, RCL A: 0.0285, RCL A: 0.0247, RCL A: -0.0206, RCL A: 0.0232, RCL A: -0.0363, RCL A: 0.0638, RCL A: 0.0277, RCL A: -0.0416, RCL A: 0.0183, RCL A: -0.0348, RCL A: 0.0439, RCL A: 0.0397, RCL A: 0.0886, RCL A: -0.0975, RCL A: 0.0319, RCL A: -0.0036, RCL A: 0.0587, RCL A: 0.0388, RCL A: -0.0482, RCL A: 0.0509, RCL A: -0.0549 Imaginary parts: RCL B: -0.0115, RCL B: -0.1044, RCL B: 0.0663, RCL B: 0.0940, RCL B: -0.1395, RCL B: -0.1038, RCL B: -0.0652, RCL B: -0.0403, RCL B: 0.0796, RCL B: 0.0945, RCL B: 0.0430, RCL B: 0.0005, RCL B: -0.0459, RCL B: -0.0329, RCL B: 0.0005, RCL B: -0.0081, RCL B: 0.1066, RCL B: -0.0765, RCL B: -0.0271, RCL B: 0.0520, RCL B: -0.0181, RCL B: 0.0712, RCL B: 0.0676, RCL B: -0.1183, RCL B: 0.0114 and so the 5x5 complex inverse matrix M' is: │ -0.1197-0.0115i -0.0070-0.1044i 0.0635+0.0663i 0.0322+0.0940i 0.0285-0.1395i │ │ 0.0247-0.1038i -0.0206-0.0652i 0.0232-0.0403i -0.0363+0.0796i 0.0638+0.0945i │ M' = │ 0.0277+0.0430i -0.0416+0.0005i 0.0183-0.0459i -0.0348-0.0329i 0.0439+0.0005i │ │ 0.0397-0.0081i 0.0886+0.1066i -0.0975-0.0765i 0.0319-0.0271i -0.0036+0.0520i │ │ 0.0587-0.0181i 0.0388+0.0712i -0.0482+0.0676i 0.0509-0.1183i -0.0549+0.0114i │ Notes:
That's all, hope you enjoyed it and found it useful for your own purposes. Comments welcome. V. All My Articles & other Materials here: Valentin Albillo's HP Collection |
|||
09-25-2023, 02:52 PM
Post: #2
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Very nice, Valentin!
You make it increasingly harder for me to improve upon your code ;-) I did manage to squeeze off a puny byte, a stack instruction, which will make little to no difference. The one thing I miss in your extensive posts, however, is some explanation of the algorithm used. So here goes, and it is based on my version of your code - which simply switches the roles of matrices E and B. To invert a complex matrix A+iB = X+iY, you need to solve A.X – B.Y = I B.X + A.Y = 0 Add and subtract: (This step is needed to make reasonably certain that the main matrix is invertible) (A+B).X - (B-A).Y = I (B-A).X + (A+B).Y = -I Let E := B - A; B := A + B; then the equations become B.X - E.Y = I (1) E.X + B.Y = -I (2) multiply (2) by E.B^-1 and add to (1): (B + E.B^-1.E).X = I - E.B^-1 multiply (1) by E.B^-1 and subtract from (2): (B + E.B^-1.E).Y = -I – E.B^-1 Then the algorithm becomes: (with double inversion to keep the number of matrices needed down to 3) E := B - A; B := (A + B)^-1; A := -E*B; B := B^-1; B := (B – A*E)^-1; E := B*A; A := E + B; B := E - B; listing (30 lines, 31 bytes): LBL C RCL MATRIX B RCL MATRIX A RESULT E - RCL MATRIX A RCL MATRIX B RESULT B + 1/x RESULT A x CHS RCL MATRIX B RESULT B 1/x X<>Y RCL MATRIX E MATRIX 6 1/x RCL MATRIX A RESULT E x RESULT A + RCL MATRIX E RCL MATRIX B RESULT B - RTN Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
09-26-2023, 10:49 AM
(This post was last modified: 09-27-2023 03:36 PM by Werner.)
Post: #3
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Shamelessly
to solve (A+iB)*(X+iY) = C+iD, enter the matrices A,B,C and D, then (GSB) D. The result will be in matrices C and D 48 lines, 52 bytes: LBL D RCL MATRIX D RCL MATRIX C RESULT E - RCL MATRIC C RCL MATRIX D RESULT C + RCL MATRIX B RCL MATRIX A RESULT D - RCL MATRIX A RCL MATRIX B RESULT B + 1/x RESULT A x CHS RCL MATRIX B RESULT B 1/x X<>Y RCL MATRIX D MATRIX 6 1/x RCL MATRIX C STO MATRIX D RCL MATRIX A RCL MATRIX E RESULT D MATRIX 6 RCL MATRIX A RCL MATRIX C CHS RESULT E MATRIX 6 RCL MATRIX B RCL MATRIX D RESULT C x RCL MATRIX B RCL MATRIX E RESULT D x RTN You can try out the above example with C the identity matrix and D all zeroes, effectively producing the inverse again. This routine, incidentally, will allow solving a 4x4 complex system on an original 15C. (and up to a 7x7 on the 15C2, or an 8x8 on the DM15L-M1B) However, the original contents of A and B are lost so you can't solve a subsequent system. Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
09-27-2023, 03:43 PM
Post: #4
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Not quite what you asked for, Valentin, but here's a short routine to multiply two split complex matrices.
Together with your inversion routine, it may be used to solve a system of equations as well. This routine multiplies the complex matrices A+iB and C+iD, and places the result in C+iD. C+iD := (A+iB)*(C+iD); on condition that A is invertible. It leaves A intact, while B may suffer some accuracy loss. (A+iB)*(C+iD) = (A.C - B.D) + i(A.D + B.C) that is impossible to do with just one extra matrix, so we have to resort to a 'trick' A.C - B.D = A*(C - A^-1.B.D) A.D + B.C = A*(D + A^-1.B.C) so we can do: E := A; B := E^-1*B; E := C; E := E - B*D; D := D + B*C; C := A*D; D := C; C := A*E; E := A*B; B := E; If you leave off the last 5 lines, B is not restored, and it's 26 lines, 31 bytes. 31 lines, 37 bytes LBL D RCL MATRIX A STO MATRIX E RCL MATRIX B RCL MATRIX E RESULT B / RCL MATRIX C STO MATRIX E RCL MATRIX B RCL MATRIX D RESULT E MATRIX 6 RCL MATRIX A RCL MATRIX B RCL MATRIX C CHS RESULT D MATRIX 6 RESULT C x STO MATRIX D RCL MATRIX A RCL MATRIX E x RCL MATRIX A RCL MATRIX B RESULT E x STO MATRIX B RTN Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
09-29-2023, 01:20 PM
(This post was last modified: 10-03-2023 07:16 AM by Werner.)
Post: #5
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
[Update: shaved off 2 bytes ;-) ]
Apologies for monopolizing this thread ;-) Forget all that came before; well, save the previous post on multiplying two complex matrices, which may still be useful as is. The following three small routines are all you need for complex matrix solving and inverting, in 'split' format. Enter matrices A,B,C and D separately as before. - to solve (A+iB)*(X+iY) = C+iD, press (GSB) C and (GSB) D - to invert A+iB, do (GSB) C and (GSB) E The GSB C part need only be done once - think of it as the LU-decomposition for regular matrices. So you can solve subsequent right-hand sides (C,D,D,..), and combine solving and inverting (C,D,D,..,E). If you leave off LBL E, you have a routine of 48 bytes for solving complex equations, and subsequent ones, if needed. This routine thus replaces the one I previously posted, which couldn't handle subsequent solves - but it still fits in an original 15C and allows solving a 4x4 complex system. (the 15CE can solve a 5x5, the 15C-2 a 7x7 and the DM15L an 8x8 system) The inversion routine alone needs 3.N^2 registers, the solve routine an additional 2N.M registers, where M is the number of right-hand side columns. So, to solve a single 4x4 system, you'd need 3.4^2+2.4 = 56 registers. Since the program of 48 bytes uses 7 additional registers, it still fits in an original 15C. Routine C (Factor) - 21 bytes Routine D (Solve) - 27 bytes Routine E (Invert) - 15 bytes for a total of 63 bytes. 001 LBL C 002 RCL MATRIX B 003 RCL MATRIX A 004 RESULT E 005 - 006 RCL MATRIX A 007 RCL MATRIX B 008 RESULT A 009 + 010 1/x 011 RESULT B 012 x 013 CHS 014 RCL MATRIX A 015 RESULT A 016 1/x 017 X<>Y 018 RCL MATRIX E 019 MATRIX 6 020 RTN 021 LBL D 022 RCL MATRIX D 023 RCL MATRIX C 024 RESULT E 025 - 026 RCL MATRIX C 027 RCL MATRIX D 028 RESULT C 029 + 030 STO MATRIX D 031 RCL MATRIX B 032 RCL MATRIX E 033 MATRIX 6 034 RCL MATRIX A 035 / 036 RCL MATRIX B 037 RCL MATRIX D 038 CHS 039 RESULT E 040 MATRIX 6 041 RCL MATRIX A 042 RESULT D 043 / 044 RTN 045 LBL E 046 RCL MATRIX B 047 RCL MATRIX A 048 RESULT E 049 / 050 RCL MATRIX A 001 RESULT A 002 1/x 053 RESULT B 054 - 055 RCL MATRIX E 056 RCL MATRIX A 057 RESULT A 058 + 059 RTN Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
10-01-2023, 11:08 PM
(This post was last modified: 10-02-2023 10:17 PM by Gerson W. Barbosa.)
Post: #6
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(09-29-2023 01:20 PM)Werner Wrote: - to solve (A+iB)*(X+iY) = C+iD, press (GSB) C and (GSB) D Thank you both, Werner and Valentín! The matrix capabilities in the HP-15C were nice, but the methods in the manual for solving complex linear systems were somewhat complicated and not easy to remember. I would need to carry the manual along to use it for that task. Doing it programmatically is a great idea, I wonder why no one thought of this back then – at least I don’t remember of any. These would have been handy when I got my 15C a few years later. Here’s a real-world example to illustrate the usage of your latest method. Perhaps not the best example as the main matrix has only real elements: Three-phase voltage source (Wye), unbalanced resistive load (Δ), line voltage = 220V. R₁I₁ + 220√3/3∠120° = 220√3/3 R₂I₂ + 220√3/3 = 220√3/3∠-120° R₃I₃ + 220√3/3∠-120° = 220√3/3∠120° R₁ = R₂ = 12.1 Ω; R₃ = 24.2 Ω A = | 12.1 0 0 | | 0 12.1 0 | | 0 0 24.2 | B = | 0 0 0 | | 0 0 0 | | 0 0 0 | C = | 190.5255888 | |-190.5255888 | | 0.000000000 | D = |-110 | |-110 | | 220 | GSB C GSB D -> X = | I₁ | | I₂ | | I₃ | = C = | 15.74591643 | |-15.74591643 | | 0.000000000 | D = |-9.090909091 | |-9.090909091 | | 9.090909091 | or I₁ = 18.18181818∠-30° I₂ = 18.18181828∠-150° I₃ = 9.090909091∠90° These are the load currents. The source currents are I₁ - I₂, I₂ - I₃ and I₃ - I₁. Edited to add three missing negative signs (corrections in red). |
|||
10-02-2023, 02:41 PM
(This post was last modified: 10-02-2023 10:15 PM by Gerson W. Barbosa.)
Post: #7
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(10-01-2023 11:08 PM)Gerson W. Barbosa Wrote: Perhaps not the best example as the main matrix has only real elements Let’s consider small inductive reactances in series with the voltage sources and get a set of equations that does require a complex system solver: (R₁ + XL₁)I₁ - XL₁I₂ + 220√3/3∠120° = 220√3/3 (R₂ + XL₂)I₂ - XL₂I₃ + 220√3/3 = 220√3/3∠-120° (R₃ + XL₃)I₃ - XL₃I₁ + 220√3/3∠-120° = 220√3/3∠120° R₁ = R₂ = 12.1 Ω; R₃ = 24.2 Ω; XL₁ = XL₂ = XL₃ = j0.1 Ω A = | 12.1 0 0 | | 0 12.1 0 | | 0 0 24.2 | B = | 0.1 -0.1 0 | | 0 0.1 -0.1 | | -0.1 0 0.1 | C = | 190.5255888 | |-190.5255888 | | 0.000000000 | D = |-110 | |-110 | | 220 | GSB C GSB D -> X = | I₁ | | I₂ | | I₃ | = C = | 15.7426645800 | |-15.8956234800 | | 0.07647945438 | D = |-9.352382547 | |-8.958908239 | | 9.155645392 | or I₁ = 18.31115909∠-30.71364707° I₂ = 18.24644849∠-150.5940233° I₃ = 9.155964813∠89.52140479° 35 seconds on my old 15C (26 s + 9 s). P.S.: When checking it upon the 48GX I noticed discrepancies in some results, starting in the third or fourth digits, plus one inconsistent angle (changed sign). It turns out that I had missed a negative sign in the beginning, when doing a polar to rectangular conversation. The element D(2.1) should be -110, not 110. Fixed. This would cause less disturbance in the previous post example, only a few sign changes, which made the error harder to detect. A closer look to the angles values would have made the inconsistency evident, though. I will correct that as well. |
|||
10-03-2023, 07:47 AM
Post: #8
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Thank you, Gerson!
In the meantime I updated my post with a new, shorter and faster (for solving, at least) version. It seems that every time I look at my code I find ways to improve it.. I also did some accuracy tests, with the example from pg 128 in the Advanced Functions Handbook, which you can now do on your original 15C: (I multiplied all values by 3 - then they are all integers): A 4x4: 300 0 0 0 0 3E6 -3E6 0 0 -3E6 3E6 0 0 0 0 3E5 B 4x4: -350 800 0 0 800 -350 0 0 0 0 442 -450 0 0 -450 442 C 4x1: 30 0 0 0 D 4x1: 0 0 0 0 exact result, rounded to 10 digits: ( 1.995795141E-4 , 4.096399085E-3) (-1.448833619E-3 , -3.563298308E-2) (-1.454083174E-3 , -3.563276083E-2) ( 5.344581171E-5 , -2.259868256E-6) built-in result (on the 15CE, 8x8 matrix): ( 1.995820000E-4 , 4.096401051E-3 ) (-1.448812372E-3 , -3.563300015E-2 ) (-1.454061929E-3 , -3.563277790E-2 ) ( 5.344583732E-5 , -2.259863892E-6 ) split solve result: ( 1.995574520E-4 , 4.096386294E-3 ) (-1.448834528E-3 , -3.563298920E-2 ) (-1.454084082E-3 , -3.563276695E-2 ) ( 5.344583458E-5 , -2.259876193E-6 ) These results are comparable. The matrix is badly conditioned, so the results are only accurate to about 5 digits. The split solve routine is slightly slower than the built-in one (without counting the necessary transformations to produce the 8x8 matrix, though!): 0.45 seconds vs. 0.36 seconds on the 15CE, but this latest version should be about 10% faster than the previous one. Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
10-03-2023, 02:28 PM
(This post was last modified: 10-03-2023 02:41 PM by Gerson W. Barbosa.)
Post: #9
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(10-03-2023 07:47 AM)Werner Wrote: In the meantime I updated my post with a new, shorter and faster (for solving, at least) version. Thanks again! Now we have a really pocket calculator suitable for this kind of task, even the original HP-15C is fast enough to handle these. It took about 30 seconds to solve my second example (20.5 s +9.5 s). Basically the same results. C = | 15.7426645800 | [-1 ULP] |-15.8956234800 | [+2 ULP] | 0.07647945442 | [+8 ULP, previously 4 ULP] D = |-9.352382547 | [-5 ULP] |-8.958908239 | [-7 ULP] | 9.155645395 | [-4 ULP] or I₁ = 18.31115909∠-30.71364707° [-1, 0 ULP] I₂ = 18.24644849∠-150.5940233° [-2, 0 ULP] I₃ = 9.155964816∠89.52140479° [-3, 0 ULP, previously -6, 0 ULP] ULP comparisons with the HP-GX results which are assumed to be more accurate, but not granted to be always exact to 12 digits. Edited to fix formatting |
|||
10-05-2023, 01:05 PM
(This post was last modified: 10-06-2023 11:28 AM by Werner.)
Post: #10
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(09-22-2023 08:22 PM)Valentin Albillo Wrote: The matrix A+B must be invertible, i.e. det(A+B) # 0. For most real-life uses this will be the case but if this condition isn't met there are slight variations to this routine that would work Ok in those cases. The problem is that the 15C alters a singular matrix slightly to produce a solution anyway, and you will probably not be aware that it did. I would've liked for this to be optional - but it has even found its way into the 42S as well... Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
10-06-2023, 03:30 AM
(This post was last modified: 10-06-2023 04:45 AM by Valentin Albillo.)
Post: #11
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Hi all, This is my 1,001th post here so I'm celebrating it with a new, significant improvement to the inversion routine I included in my original post, but first a few comments are in order, as after a slow start this thread has been gathering momentum by the day. Let's see: Werner Wrote:You make it increasingly harder for me to improve upon your code ;-) I did manage to squeeze off a puny byte [...] The one thing I miss in your extensive posts, however, is some explanation of the algorithm used. [...] Shamelessly Thanks for your interest, Werner, I hope you're enjoying your new HP-15C CE and do not regret your purchase at all. It certainly seems to have boosted your inspiration. As for the algorithms, as I said I leave that math-heavy discussion for the future article out of consideration for people who just want to use the code and don't care for its innards. As for squeezing off a puny byte, well, that's your specialty. See if you can oblige in my new code below. And as for stealing/ Werner Again Wrote:Not quite what you asked for, Valentin, but here's a short routine to multiply two split complex matrices. Very nice, and yes, I was expecting a simple piece of code that would use conventional nested loops to perform the multiplication by taking advantage of the 15C's native complex arithmetic, that's why I left it as an easy exercise for the reader. As it wouldn't involve matrix inversion, it should run fast and accurately. Werner Once More Wrote:[Update: shaved off 2 bytes ;-) ] Apologies for monopolizing this thread ;-)] [...] to invert A+iB, do (GSB) C and (GSB) E [...] Routine C (Factor) - 21 bytes [...] Routine E (Invert) - 15 bytes No need to apologize for monopolizing, I'm used to it by now. And congratulations for the 2-byte savings, it's no mean feat and I know you enjoy doing it. Per your figures, it seems you need to call two routines to invert a complex matrix, totalling 36 bytes in all, which is nice taking into account that routine C is also used to solve a complex system if C is called first so C serves double duty. However, just inversion alone can be done by calling a single 21-byte routine, as I show below. Gerson Wrote:The matrix capabilities in the HP-15C were nice, but the methods in the manual for solving complex linear systems were somewhat complicated and not easy to remember [...] Doing it programmatically is a great idea, I wonder why no one thought of this back then [...] Thanks a lot for your great 4x4 EE examples for the original HP-15C, Gerson. The methods in the manual (both the OH and the AFH) are wholly inadequate: extremely cumbersome, very difficult to remember when you needed them, outrageously complicated and requiring several ad-hoc pre- and post-transformations, but the worst of all was their enormous inefficiency, turning an NxN complex matrix into a 2Nx2N real one, doubling the memory required and more than doubling the computing time. In short, a very poor performance by HP in the OH, and the AFH is no better in that regard. And as for "I wonder why no one thought of this back then", I did, but when the HP-15C was introduced (1982) I had alreay left PPC (and PPC TN) so I had nowhere to submit any further articles, plus I didn't have the money for a 15C or a 71B or any other HP model with complex/matrix capabilities to implement my ideas, nor was I able to until 1985 and afterwards it took me several years to join the MoHPC forum and it's only now that the 15C CE has appeared (with its tremendous 180x speed and 3x the memory,) that I considered worthwhile and interesting to dust off my old notes, implement them and post the results here. So here you are, the announced improvement ... The improvement: Complex Matrix Inversion up to 8x8 in 21 bytes The complex matrix inversion routine I included in my original post is nice and fast and all that jazz, and even quite short at 31 steps (32 bytes, 5 regs), but it's a bit conservative and thus somewhat longish and I can do better by selecting a different variant, as I'll explain right now. The thing with complex inversion routines based on this specific split-matrix approach (M = A + iB) is that they require inverting some real matrices (say A or B or A+B or A-B or a random linear combination of A and B, etc.) and thus said matrices must be invertible (i.e. non-singular i.e. det#0). The good point is that we get to choose which matrix must be invertible, and if the complex matrix includes that component or combination and it happens to be singular, we can choose another that isn't, which would of course require a variant of the inversion routine. Needless to say, all of this only applies if complex M is invertible even if real A or B (say) are not, but even if both are singular it might be the case that M is not and thus can be inverted using the particular routine which requires A+B (for instance) to be invertible, which is the 31-step routine featured in my original post. But that routine can be significantly shortened (by some 11 steps no less, 33% shorter) by assuming that A is invertible (which for real-life problems is usually the case and for random matrices is always the case,) i.e. det(A)#0, and here's the resulting improved complex inversion routine (which, as detailed below, can also be used when A is singular but B is not by means of a simple trick): Program listing This 20-step (21-byte, 3-reg) routine can be used to invert an NxN complex matrix M = A + iB when A is invertible, and also when A is singular but B is invertible using a simple trick, see details below. LBL C 001- 42,21,13 RESULT A 002- 42,26,11 RCL MATRIX E 003- 45,16,15 RCL MATRIX B 004- 45,16,12 RCL MATRIX A 005- 45,16,11 1/x 006- 15 RESULT E 007- 42,26,15 x 008- 20 RESULT A 009- 42,26,11 CHS 010- 16 RCL MATRIX B 011- 45,16,12 LASTX 012- 43 36 1/x 013- 15 R▼ 014- 33 MATRIX 6 015- 42,16, 6 1/x 016- 15 RESULT B 017- 42,26,12 X<>Y 018- 34 x 019- 20 RTN 020- 43 32 Changes in the documentation I could have edited the docs in my original post to cater for this new routine but that's not my personal policy; unlike most people I only edit a post to correct typos or blatant errors, never to change, remove or add significant contents. Besides, the original documentation fully applies to my original 31-step routine which is the one to use if both A and B are singular but A+B is not, so its docs will remain as they currently are. What I'll do here is to specify the changes in the docs pertaining to this new 20-step routine, including for context the abridged paragraphs where they appear, with the changed parts in bold red. You should still refer to the original docs for everything else (Notes, Requirements, Worked Example, etc.) Changes in Notes:
Using this routine when A is singular but B is not As I explained above, usually different variants of my complex inversion routine are needed depending on whether (1) A is invertible, or (2) A is singular but B is invertible, or (3) both A and B are singular but A+B (or A-B) is invertible. My original 32-byte routine somewhat conservatively addressed the third case, where A and B can both be singular as long as A+B isn't (a slightly-different, same-length variant would handle the invertible A-B case.) Now, my new 21-byte routine caters for the first case (A is invertible.) The second case (A is singular but B is invertible) can be dealt with using a near-symmetric same-length variant of the routine but actually there's no need to have two almost-identical routines in memory at once, as a simple trick will allow the present one to also handle the second case (A singular, B invertible), just proceed like this: To compute using this routine the complex inverse of M = A + iB when A is singular but B is invertible:
That's all. I've missed a few usual suspects posting here but that's life, no hard feelings . As always, hope you enjoyed it. V. Edit: a few typos. All My Articles & other Materials here: Valentin Albillo's HP Collection |
|||
10-06-2023, 11:23 AM
Post: #12
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(10-06-2023 03:30 AM)Valentin Albillo Wrote: (..) See if you can oblige in my new code belowI have to live up to my reputation, don't I? 18 lines, 19 bytes: 001 LBL C 002 RCL MATRIX E 003 RCL MATRIX B 004 RCL MATRIX B 005 RCL MATRIX A 006 RESULT E 007 / 008 CHS 009 RCL MATRIX A 010 RESULT A 011 1/x 012 1/x 013 Rv 014 MATRIX 6 015 1/x 016 RESULT B 017 x 018 RTN Personally, however, I prefer the previous, slightly longer code. It offers more protection against degenerate systems, especially since, as I mentioned before, the 15C does not alert you when it encounters one, but alters it slightly so as to be able to come up with *a* solution - even if it is only one of infinitely many. Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
10-06-2023, 02:51 PM
(This post was last modified: 10-06-2023 03:05 PM by J-F Garnier.)
Post: #13
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
I'm amazed by these little pieces of code posted by Valentin (congrats for your 1000 - now 1001 - posts !) and Werner.
I really appreciate short, powerful routines that expand the possibility of a machine. And this is exactly the case here: the first thread from Valentin was providing a workaround for the 8x8 limit for real matrix inversion. Then this second thread goes further by getting the utmost from the limited memory of the HP-15c in the case of complex matrices. In the case of the 15c CE/192, this makes a difference and allows to manage 7x7 matrices instead of 6x6. An hypothetical 15c CE/224 could even handle 8x8 matrices. J-F |
|||
10-06-2023, 05:37 PM
Post: #14
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(09-29-2023 01:20 PM)Werner Wrote: So, to solve a single 4x4 system, you'd need 3.4^2+2.4 = 56 registers. Since the program of 48 bytes uses 7 additional registers, it still fits in an original 15C. I’ve tried a 4x4 system on mine but it would stop with an Error 10 message on the display. MEM shows 1 15 9-0. Not a problem for the HP-15C CE (MEM: 19 25 09-9 after program completion). Problem is both det(A) and det(B) in that particular system are zero. It does give a solution, but it looks meaningless to me: A = | 12.1 0.0 0.0 12.10 | | 0.0 12.1 0.0 12.10 | | 0.0 0.0 24.2 24.20 | | 12.1 12.1 24.2 48.4| B = | 0 0 0 0 | | 0 0 0 0 | | 0 0 0 0 | | 0 0 0 0 | C = | 220 | |-110 | |-110 | | 0.0 | D = | 0.000000000 | | 190.5255888 | |-190.5255888 | | 0.000000000 | => C = | 5.425143454 | | 13.47770233 | |-24.62741542 | |-5.425143453 | D = | 4.514866980 | | 34.56742586 | |-3.537691900 | |-4.514866980 | or I₁ = 7.058059602∠39.76761789° I₂ = 37.10195939∠68.69938684° I₃ = 24.88021009∠-171.8254666° I₄ = 7.058059601∠-140.2323821° These may be a valid solution (I haven’t checked them out), but they don’t appear to be the solution for the problem I was trying to solve. In an attempt to circumvent that I changed slightly the last element of matrix A, which managed to give results very close to the values I expected. I still have to doublecheck my equations for a possible mistake. A = | 12.1 0.0 0.0 12.100 | | 0.0 12.1 0.0 12.100 | | 0.0 0.0 24.2 24.200 | | 12.1 12.1 24.2 48.39| => C = | 18.18181621000000 | |-9.090911560000000 | |-4.545456889000000 | | 0.000002180000421 | D = |-0.000004626165054 | | 15.74591168000000 | |-7.872962425000000 | | 0.000004820000930 | or I₁ = 18.18181621∠-0.000014578° I₂ = 18.18181530∠120.0000142° I₃ = 9.090913908∠-119.9999995° I₄ = 0.00000529007∠65.66360913° and Ir₁ = I₁ + I₄ = 18.18181839∠0.0000006111° Ir₂ = I₂ + I₄ = 18.18181838∠120.0000007° Ir₃ = I₃ + I₄ = 9.09090864376 ∠-120.00000279° |
|||
10-06-2023, 07:38 PM
Post: #15
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Hi Gerson,
To solve a 4x4 system on an original 15C, you have to leave off the inversion code LBL E. I see you used up 9 registers for programs, so you used the full 63 bytes and then there’s not enough room left to solve the system. LBL C and D together only take 48 bytes so less than 7 registers, and then it will work (with 1 DIM (i) ). And yes, when A+B is singular you get a meaningless answer, unfortunately. The example you gave however, is rank-deficient anyway as B=0 and det(A)=0, so in this case there is no workaround, save a Least Squares solution, which is a different beast altogether. Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
10-06-2023, 08:20 PM
(This post was last modified: 10-07-2023 11:26 AM by Gerson W. Barbosa.)
Post: #16
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
(10-06-2023 07:38 PM)Werner Wrote: And yes, when A+B is singular you get a meaningless answer, unfortunately. The example you gave however, is rank-deficient anyway as B=0 and det(A)=0, so in this case there is no workaround, save a Least Squares solution, which is a different beast altogether. Hello, Werner, Thanks for the enlightenment! Anyway, I was able to get answers very close to the exact results, currents equal to 200/11 A and 100/11 A, shifted 120 degrees from each other. In this latest example instead of a wye I considered a delta three-phase voltage source. As a result, rather than a simple 3x3 system that could be solved by hand, I ended up with a more complicated 4x4 system. If not for anything else, at least another opportunity to use the new VW complex equation solver :-) Best regards, Gerson. P.S.: I made indeed a mistake in the previous example by introducing an extra unnecessary equation. Time for solving a 3x3 system on the original 15C is 32 seconds, not 30 as I said earlier; 56 second for a 4X4 system. Instantly on the 15C CE. |
|||
10-11-2023, 12:46 AM
Post: #17
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Hi, all, This thread's got a number of new posts so some comments ... First Werner "2-byte" Proudly Wrote:I have to live up to my reputation, don't I? Indeed you did, shaving off 2 bytes from my original code once again. That's the third or fourth time in a row so I think you've earned yourself the "2-byte" moniker. Some remarks on your 18-step code vs. my 20-step routine:
Well, I have ! These are the results:
Then J-F Garnier Wrote:I'm amazed by these little pieces of code posted by Valentin (congrats for your 1000 - now 1001 - posts !) and Werner. Thanks, J-F. I was missing your comments. Quote:I really appreciate short, powerful routines that expand the possibility of a machine. And this is exactly the case here: the first thread from Valentin was providing a workaround for the 8x8 limit for real matrix inversion. With the HP-15C original and CE editions not having any sort of mass storage, it's vital that the programs are as short as possible lest no one will bother to key them in, not even to just try them out, as it would be such a lengthy, error-prone chore. And something had to be done about that annoying 8x8 limit, so partitioned matrices immediately sprang to mind. Quote:Then this second thread goes further by getting the utmost from the limited memory of the HP-15c in the case of complex matrices. In the case of the 15c CE/192, this makes a difference and allows to manage 7x7 matrices instead of 6x6. An hypothetical 15c CE/224 could even handle 8x8 matrices. On the other hand, a not-so-hypothetical-but-actually-extant DM15 clone with firmware M1B (229 regs) can handle 8x8 complex matrices (and perhaps even systems of 8 complex equations in as many complex unknowns.) And if the CE/192 user is not afraid of manually typing in just 16 or 18 instructions, he/she can invert an 8x8 complex matrix in the CE/192 as well, it'll take just a little care and likely less than 2 min. BTW, it's a real pity HP didn't make the index registers R0, R1 and RI allocatable because that would've left just enough program space for the complex inversion routine itself so no need for manually typing in anything. It's also a pity that Moravia didn't allow for the max. 229 registers in the CE, as SwissMicros did. The 37 extra regs might come in handy for everything, 8x8 complex matrix handling in particular. Perhaps this capability was intentionally left for a future HP-15C CE 2.0 version including
Best regards. V. All My Articles & other Materials here: Valentin Albillo's HP Collection |
|||
10-11-2023, 03:11 PM
Post: #18
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Hi Valentin.
(10-11-2023 12:46 AM)Valentin Albillo Wrote: [..] my original code only subjects matrix A to two inversion procedures instead of your three procedures detailed above, so I feel that your code's accuracy might be slightly degraded (whether the matrix is degenerate or not,) and I also wonder if your routine's speed is negatively affected. Have you checked any of this ? I didn't run simulations because I knew that the results would be comparable in accuracy and timing.
Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
10-11-2023, 04:54 PM
Post: #19
|
|||
|
|||
RE: [VA] SRC #015b - HP-15C & clones: COMPLEX Matrix Inverse up to 8x8
Hello!
(10-11-2023 12:46 AM)Valentin Albillo Wrote: That way they'd easily milk yet another 130 € apiece from each of us ... I can guarantee that the next one is going to cost more than 130 Euros, especially if it comes with a printed colour book! Books like that now tend to cost in excess of 30 Euros, especially if they are made in small numbers. And they are not getting cheaper. But most important, thanks for the effort of sharing your program(s) with us - and Werner of course as well! This really makes a lot more sense than the method from the original manual. If anything, I would want these routines hardwired into the ROM of the next version of the 15C! Regards Max |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 7 Guest(s)