Newsgroups: comp.lang.apl
Path: watmath!watserv2.uwaterloo.ca!torn!howland.reston.ans.net!darwin.sura.net!news-feed-1.peachnet.edu!umn.edu!csus.edu!sfsuvax1.sfsu.edu!vpcsc4
From: vpcsc4@sfsuvax1.sfsu.edu (Emmett McLean)
Subject: Re: Question: Tri-diagonal matrices in APL
Message-ID: <1993May6.030445.3577@csus.edu>
Sender: news@csus.edu
Organization: San Francisco State University
References: <1684@kepler1.rentec.com> <1993Apr29.235958.5696@csus.edu> <1695@kepler1.rentec.com>
Date: Thu, 6 May 1993 03:04:45 GMT
Lines: 184



Apologies to those of you who subscribe to comp.lang.apl .
I posted a response, and after thinking about Andrew Mullhaupt's
comments, felt my post did not represent the best way of thinking
about these things. 

In article (Andrew Mullhaupt) writes:
>
>Irrelevant. The code is already written, polished, published and ready
>to run.

 This is true, and it probably is not terribly difficult to call
 compiled FORTRAN from your favorite language.  

>
>> LAPACK has a long learning curve associated with it.
>
>So does numerical linear algebra; but it you need to use numerical linear
>algebra, the way to make the fewest mistakes is to use LAPACK (and the
>manual) instead of rolling your own.

 LAPACK is widely used and highly regarded in the Mathematical community. 
 For this reason alone I agree.
>
>> And finally, if you are in an environment where you are restricted 
>> with the amount of memory you can use, forget using LAPACK.
>
>This is a joke right? 

 Actually I was refering to running a package on a machine with limited
 memory, like an HP-95LX. I suppose if you are selective about which
 programs from LAPACK you are using you can find room for the source
 and the executables. Not a big deal.

I'm supposed to use less memory in J? Aside from the
>excess copying scandal, etc., let's consider that you posted a computation
>of the _inverse_ of the tridiagonal matrix which uses NxN=N^2 elements
>but the LU decomposition requires 2N-2 elements. Now in order for this
>to be _more_ memory you require:
>
>		2N-2 > N^2
>
>Note that this cannot happen for any integer N > 0.

 This is correct. But an efficient LU decomposition can just as readily
 be coded in APL, (or even better C) than in FORTRAN. However, if speed
 is important FORTRAN will be better to use.

>referring to some temporary scratch space? Well good news there - LAPACK
>isn't going to need _any_ if you want the result in place, (which can
>easily be arranged). 

>Can you say this for APL or J?

APL can do this in place, J can but not easily.

>Don't come crying
>to me if APL of J needs to copy or serialize the data in order to pass
>it safely in and out of LAPACK. That's not necessary if your APL or J
>supports dynamic loading, (which is the correct way to do this).

 Where do I get information on dynamic loading? And that efficient
 memory allocation scheme mentioned earlier?
>
>Perhaps you can elaborate on how your concern for space fits in with using
>an O(N^2) space computation (inverse of tridiagonal) where an O(N)
>computation (LU decomposition of same) would do?
>
 I was wrong. But, kind of from an asthetic point of view, I liked the
 pattern of numbers in the multiplicative inverse.

 For those of you who missed my cancelled post, you may find this of
 interest. I intended for it to be an example of how APL'ers can avoid
 the bottleneck, but if efficiency is important, this may not be very.
 Use LAPACK like Andrew says.


   NB.    Step 0. Look at the pattern of the inverse of the given
          tridiagonal. For :
           2 _1 0  0
          _1  2 0  0
           0 _1 2 _1
           0 0  _1 2

          The multiplicative inverse is 1/5 times :
          4 3 2 1
          3 6 4 2
          2 4 6 3
          1 2 3 4

   NB. Step 1. Create the following matrix
   (|.@(*/~))@>:@i. 4
4 8 12 16
3 6  9 12
2 4  6  8
1 2  3  4
   
   NB.    Step 2. Create two matrices, the above matrix and it's transpose:
   ((|:"2 ,: ])@(|.@(*/)~))@>:@i. 4
 4  3  2  1
 8  6  4  2
12  9  6  3
16 12  8  4

 4  8 12 16
 3  6  9 12
 2  4  6  8
 1  2  3  4
   
   NB.     Step 3. Match up the atoms of the above result with the
   NB.             desired boolean elements:
   ((</~ ,: >:/~) ; ((|:"2 ,: ])@(|.@(*/)~)))@>:@i. 4
+-------+-----------+
|0 1 1 1| 4  3  2  1|
|0 0 1 1| 8  6  4  2|
|0 0 0 1|12  9  6  3|
|0 0 0 0|16 12  8  4|
|       |           |
|1 0 0 0| 4  8 12 16|
|1 1 0 0| 3  6  9 12|
|1 1 1 0| 2  4  6  8|
|1 1 1 1| 1  2  3  4|
+-------+-----------+
   NB.   Step 4. sum over the matrices:
   +/@((</~ ,: >:/~) * ((|:"2 ,: ])@(|.@(*/)~)))@>:@i. 4
4 3 2 1
3 6 4 2
2 4 6 3
1 2 3 4
   NB.   Define the verb for finding the inverse:
         (The matrix above divided by n+1 , which in this case is 5 :
   inv =. +/@((</~ ,: >:/~) * ((|:"2 ,: ])@(|.@(*/)~)))@>:@i. % >:
  
 
   
   NB. Check the results
   tri =. ,~ $ (2 _1&,)@(,&_1)@(-&2 # 0:)
   
   (tri +/ .* inv) 4    
           1            0 0           0
 6.93889e_18            1 0           0
_3.46945e_18 _6.93889e_18 1 1.38778e_17
           0            0 0           1
   
   NB. Lets compare to J's indigenous matrix inversion verb
   
   time =. 6!:2
   space =. 7!:2@]
   test =. time,space
   
   test '(tri +/ .* inv) 100'
3.36 743304
   
   test '(%. +/ .* inv) 100'
0.63 743240
  
Well, %. seems to win the performance contest but how abut
the accuracy contest :
   
Define a verb for the identity matrix :
   id =. ,~ $ (1&,)@( # 0:)
   id 3
1 0 0
0 1 0
0 0 1
   
NB. So if we determine the difference between the identity 
NB. matrix created by matrix multiplication, subtract off
NB. the identity matrix, ravel, take absolute values, and sum :

   +/@|@,@(id - (tri +/ .* inv)) 100
8.57688e_13
   +/@|@,@(id - (%. +/ .* inv)) 100
85752

Conclusion.

The formula may be slower than the indigenous inversion but
far more accurate.



Emmett
